Java IO

本文记录了在学习Java IO过程中的知识点,用于复习和快速查阅,不够详细的部分可能会在后续补充。

什么是流

流:内存与存储设备(外存)之间传输数据的通道

IO:输入流输出流(如read, write)

流分类(按单位):

  • 字节流:以字节为单位,可以读写所有数据
  • 字符流:以字符为单位,只能读写文本数据

流分类(按功能):

  • 节点流(底层流):具有实际传输数据的读写功能
  • 过滤流:在节点流的基础之上增强功能

字节流

字节流的父类(抽象类)有:InputStream, OutputStream

  • FileInputSteam:

publib int read(byte[] b) 从流中读取多个字节,将读取内容存入b数组,返回实际读到的字节数;若达到文件尾部,则返回-1;读取的数量和b的大小也有关

具体方法可见JDK文档,以下代码需要加上异常处理

        FileInputStream fis = new FileInputStream("a.txt");  //这里不是与class文件的同目录,需再考察,需写绝对路径
int data = 0;
// while((data = fis.read()) != -1){ //一次只读一个字符
// System.out.println(data);
// }
byte []a =new byte[3];
int count = fis.read(a);
for(Object ob : a){
System.out.println(ob);
}
System.out.println(count); byte []b =new byte[3];
count = fis.read(b);
for(Object ob : b){
System.out.println(ob); //读两次,第二次是3-6段的字符 和C相似,类似文件指针
}
System.out.println(count);
fis.close();
System.out.println("end");
  • FileOutputSteam:

publib int write(byte[] b) 一次写入多个字节,将b数组中所有字节,写入输出流,返回值为实际读到的字节数

FileOutputStream fio = new FileOutputStream("a.txt");  //直接覆盖原文件,原有内容消失
fio.write(97);
fio.write('b');
String a = "hello,world";
fio.write(a.getBytes()); //这里需要将字符串转为 Byte[]
fio.close();
System.out.println("ending");

FileOutputStream("a.txt")改为("a.txt",true)将不会覆盖原文件,保有原有内容

字节缓冲流

BufferedInputStream, BufferedOutputStream 父类是过滤流

当创建BufferedInputStream时,将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。mark操作会记住输入流中的一点,并且reset操作会导致从最近的mark操作之后读取的所有字节在从包含的输入流中取出新的字节之前重新读取。

  • 提高IO效率,减少访问磁盘的次数
  • 数据存在缓冲区,flush是将缓冲区的内容写入文件,也可以直接close
BufferedInputStream(inputStream)  //需要传入一个输入流
FileInputStream fis = new FileInputStream("a.txt");  //这里需要绝对路径
BufferedInputStream bis = new BufferedInputStream(fis); //增强fis
int data = 0;
while((data = bis.read())!=-1){
System.out.print((char)data);
}
bis.close();

先把一部分内容读到缓冲区,再在缓冲区进行read, write操作,只需要关闭bis即可

BufferedOutputStream

  • 该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("hello,world".getBytes()); //写入了8K的缓冲区
bos.flush(); //刷新到外存,正式写入了
bos.close(); //即使上方没有flush();在close()中也会再刷新一次

对象流

ObjectInputStream/ObjectOutputStream

  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串的功能
  • 增强了读写对象的功能:readObject() 从流中读取一个对象;writeObject(Object obj) 向流中写入一个对象

使用流传输对象的过程成为序列化(write)、反序列化(read)

ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s1 = new Student("xiaohong",12);
oos.writeObject(s1);·
oos.close();
  • 使用对象流时,需要将类实现Serializable接口(序列化类中的属性也需要实现该接口),例
public class Student implements Serializable    //此接口内部没有方法,只是声明一下

否则将会出现不可序列化的异常

  • 序列化版本号ID,可以保证序列化的类和反序列化的类是同一个类
private static final long serialVersionUID = 100L;

如果序列化之后,ID已固定,若改变ID,则不能反序列化,除非再次用改变后的ID再进行序列化

反序列化demo:

ObjectInputStream ois = new ObjectInputStream(fis);
Student s = (Student) ois.readObject();
ois.close();
System.out.println(s.toString());
  • 反序列化的过程中,Student类也需要实现Serializable接口

  • 使用transient修饰属性,则这个属性不能序列化,在序列化过程中,如果哪个属性不想被序列化,可加此修饰符

  • 静态属性也不能序列化

  • 序列化多个对象,可借助集合实现

字符流

  • 字符编码

ISO-8859-1收录除ASCII外,还包括西欧、希腊语等对应的文字符号, UTF-8针对Unicode码表的可变长度字符编码, GV2312简体中文, GBK简体中文、扩充, BIG5繁体中文

当编码方式和解码方式不一致,会出现乱码

FileInputStream fis = new FileInputStream("a.txt"); //此处为绝对路径,存储了4个汉字“好好学习”,12个字节,UTF-8编码
int count = 0;
while((count = fis.read())!= -1){
System.out.println((char)count); //会输出乱码,因为每次输出一个字节
}

字符流的父类(抽象类):Reader/Writer

char型变量是用来存储Unicode编码的字符的,unicode 编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字。

不过,如果某个特殊的汉字没有被包含在 unicode 编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。

说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。

FileReader fir = new FileReader("a.txt");  //文件字符输入流
int count = 0;
while((count = fir.read())!= -1){
System.out.print((char)count); //注意,txt文件需要使用UTF-8编码
}
fir.close();

文件字符输入流如上所示

也可以用字符数组,如下

int count = 0;
char[] buf = new char[1024];
while((count = fir.read(buf))!= -1){
System.out.print(buf); //注意,txt文件需要使用UTF-8编码
}

字符复制(只能复制文本文件,不能复制图片等二进制文件)

FileReader fir = new FileReader("a.txt");  //文件字符输入流
FileWriter fiw = new FileWriter("b.txt");
int count = 0;
char[] buf = new char[1024];
while((count = fir.read(buf))!= -1){
fiw.write(new String(buf).trim()); //注意,txt文件需要使用UTF-8编码
}
fir.close();
fiw.close();

fiw.close()时会调用fiw.flush(),trim()时为了消除char[1024]的空白字符

字符缓冲流

BufferedReader/BufferedWriter

  • 高效读写
  • 可支持换行符
  • 可一次写一行/读一行 (readLine)

newLine(写入一个行分隔符)

        FileReader fir = new FileReader("a.txt");
BufferedReader bir = new BufferedReader(fir);
int count = 0;
char[] s = new char[1024];
// while((count=bir.read(s))!= -1){
// System.out.println(new String(s).trim());
// }
String s1 = bir.readLine();
System.out.println(s1);

两种读取方式

biw.write(s1);
biw.newLine(); //写入一个换行符
biw.close(); //附带刷新

BufferedWriter的使用示例如上

打印流

PrintWriter继承Writer

  • 将对象的格式表示打印到文本输出流。 这个类实现了PrintStream中所有的print方法。 它不包含用于编写原始字节的方法,程序应使用未编码的字节流。
PrintWriter pw = new PrintWriter("b.txt");
pw.println(97);
pw.println(true);
pw.println('a'); //需要刷新
pw.close();

也包含.write()方法。

转换流

InputStreamReader/OutputStreamWriter(名字即InputStream+Reader,桥梁)

  • 可将字节流转换为字符流
  • 可设置字符的编码方式
FileInputStream fis = new FileInputStream("a.txt");  //文件是UTF-8编码
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
int count;
char[] s = new char[1024];
while((count = isr.read(s))!=-1){
System.out.println(new String(s,0,count));
}
isr.close();

使用上大致相同

ANSI即为GBK编码方式

OutputStreamWriter中的write则会根据编码方式,自动将文件转为此类编码方式

File类

代表物理盘符中的一个文件或文件夹

以上为常用的方法,具体方法请访问JDK文档

具体使用:

  1. 分隔符
  2. 文件操作
  3. 文件夹操作

路径分隔符;

名称分隔符\

相对路径在与SRC文件的同级目录下

        File f = new File("c.txt");
System.out.println(f);
// if(!f.exists()){
// boolean bo = f.createNewFile();
// System.out.println(bo);
// }
// f.delete(); //boolean
// f.deleteOnExit();// JVM退出时自动删除
System.out.println(f.getAbsoluteFile());
System.out.println(f.getPath());
System.out.println(f.getName());
System.out.println(f.getParent()); //File类的String中不包含父目录时输出Null
System.out.println(f.length());
System.out.println(new Date(f.lastModified()));
//判断
System.out.println("是否可写"+f.canWrite());
System.out.println("是否隐藏"+f.isHidden());

File类测试用例,结果如下

文件夹操作

        File dir = new File("cc\\dd");
if(!dir.exists()){
// dir.mkdir(); //只能创建单级目录
dir.mkdirs(); //可创建多级目录
}
// dir.delete();
//遍历文件夹
File dir2 = new File("C:\\Users\\GaoYuan\\Pictures");
String[] files = dir2.list();
for(String s : files){
System.out.println(s);
}

其余操作与File类相同

FileFilter接口

File[]files = dir2.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".jpg")){
return true;
}
return false;
}
});
for(File f1 : files){
System.out.println(f1.getName());
}

添加一个过滤器,注意的是.listFiles返回的是一个File[]

Properties

属性集合,继承HashTable,可保存在流中或在流中加载

  • 存储属性名和属性值
  • 属性名和属性值都是字符串类型
  • 没有泛型
  • 和流有关
Properties properties = new Properties();
properties.setProperty("use","xiaoli");
properties.setProperty("age","20");
properties.setProperty("address","china");
System.out.println(properties);
Set<String> proname = properties.stringPropertyNames();
for(String pro : proname){
System.out.println(pro+"="+properties.getProperty(pro));
}
PrintWriter pw = new PrintWriter("b.txt");
properties.list(pw);
pw.close();

Properties,list()将该属性集合打印到输入流中,close()进行刷新写入文件

保存方法:

FileOutputStream fos = new FileOutputStream("store.properties");
properties.store(fos,"注释");
fos.close();

加载方法:

Properties properties1 = new Properties();
FileInputStream fis = new FileInputStream("store.properties");
properties1.load(fis);
System.out.println(properties1);
fis.close();

一文简述Java IO的更多相关文章

  1. 一文理解Java IO/NIO/AIO

      目录 概述 一.IO流(同步.阻塞) 二.NIO(同步.非阻塞) 三.NIO2(异步.非阻塞) 正文 概述 在我们学习Java的IO流之前,我们都要了解几个关键词 同步与异步(synchronou ...

  2. 一文简述JAVA内部类和异常

    内部类和异常 内部类 在一个类的内部定义的一个类,例如,A类中定义了一个B类,则B类相对于A类就是内部类,而A类相对于B类就是外部类 成员内部类 静态内部类 局部内部类 匿名内部类 成员内部类 pub ...

  3. Java IO 流总结篇

    1. 写在前面的话 I/O ,I 是 Input (输入)的缩写,O是Output (输出) 的缩写,众所周知,人与人之间想要沟通交流,就需要讲彼此都能听懂的语言,比如大家都统一说英语. 人类如果想和 ...

  4. 一文看懂java io系统 (转)

    出处:  一文看懂java io系统   学习java IO系统,重点是学会IO模型,了解了各种IO模型之后就可以更好的理解java IO Java IO 是一套Java用来读写数据(输入和输出)的A ...

  5. 一文带你熟悉JAVA IO这个看似很高冷的菇凉

    Java IO 是一个庞大的知识体系,很多人学着学着就会学懵了,包括我在内也是如此,所以本文将会从 Java 的 BIO 开始,一步一步深入学习,引出 JDK1.4 之后出现的 NIO 技术,对比 N ...

  6. java io 好文传送

    转自:白大虾 地址:https://www.cnblogs.com/baixl/p/4170599.html 主要内容 java.io.File类的使用 IO原理及流的分类 文件流 FileInput ...

  7. Java IO之字符流和文件

    前面的博文介绍了字节流,那字符流又是什么流?从字面意思上看,字节流是面向字节的流,字符流是针对unicode编码的字符流,字符的单位一般比字节大,字节可以处理任何数据类型,通常在处理文本文件内容时,字 ...

  8. [Java IO]03_字符流

    Java程序中,一个字符等于两个字节. Reader 和 Writer 两个就是专门用于操作字符流的类. Writer Writer是一个字符流的抽象类.  它的定义如下: public abstra ...

  9. [Java IO]02_字节流

    概要 字节流有两个核心抽象类:InputStream 和 OutputStream.所有的字节流类都继承自这两个抽象类. InputStream 负责输入,OutputStream 负责输出. 字节流 ...

随机推荐

  1. 知名金融媒体采访行业大咖,多方推动BGV茁壮成长

    近来,多家知名金融媒体如纽约金融时报.伦敦金融时报等采访NGK官方代表洛索斯夫,以及美国当地行业大咖马库斯等人. 受访的NGK官方代币洛索斯夫回答道,近期官方将会推出NGK的书籍<NGK公链底层 ...

  2. HTTP 1.x 学习笔记 —— Web 性能权威指南

    HTTP 1.0的优化策略非常简单,就一句话:升级到HTTP 1.1.完了! 改进HTTP的性能是HTTP 1.1工作组的一个重要目标,后来这个版本也引入了大量增强性能的重要特性,其中一些大家比较熟知 ...

  3. idea快捷键:查找类中所有方法的快捷键

    查找类中所有方法的快捷键 第一种:ctal+f12,如下图 第二种:alt+7,如下图

  4. Mysql训练:where后不可以进行聚合函数的判断,而having可以进行聚合函数的判断

    力扣题目:查找重复的电子邮箱 编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱. +----+---------+ | Id | Email | +----+---------+ | ...

  5. 用量子计算模拟器ProjectQ生成随机数,并用pytest进行单元测试与覆盖率测试

    技术背景 本文中主要包含有三个领域的知识点:随机数的应用.量子计算模拟产生随机数与基于pytest框架的单元测试与覆盖率测试,这里先简单分别介绍一下背景知识. 随机数的应用 在上一篇介绍量子态模拟采样 ...

  6. dubbo实战之一:准备和初体验

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. [数据结构与算法-15]单源最短路径(Dijkstra+SPFA)

    单源最短路径 问题描述 分别求出从起点到其他所有点的最短路径,这次主要介绍两种算法,Dijkstra和SPFA.若无负权优先Dijkstra算法,存在负权选择SPFA算法. Dijkstra算法 非负 ...

  8. Java 面向对象 04

    面向对象·四级 多态的概述及其代码实现 * A:多态(polymorphic)概述 * 事物存在的多种形态 * B:多态前提 * a:要有继承关系 * b:要有方法重写 * c: 要有父类引用指向子类 ...

  9. 微信小程序自定义Tabber,附详细源码

    目录 1,前言 2,说明 3,核心代码 1,前言 分享一个完整的微信小程序自定义Tabber,tabber按钮可以设置为跳转页面,也可以设置为功能按钮.懒得看文字的可以直接去底部,博主分享了小程序代码 ...

  10. 性能追击:万字长文30+图揭秘8大主流服务器程序线程模型 | Node.js,Apache,Nginx,Netty,Redis,Tomcat,MySQL,Zuul

    本文为<高性能网络编程游记>的第六篇"性能追击:万字长文30+图揭秘8大主流服务器程序线程模型". 最近拍的照片比较少,不知道配什么图好,于是自己画了一个,凑合着用,让 ...