I/O流
理解流
ATM机器,数据保存在内存中,一旦系统运行完毕,或者中途中断退出,当前操作的数据将全部消失,下次在进行访问数据已经丢失。
如果要将数据保存起来,要用流的操作,文件的操作
流的概念:java程序中当需要读取数据的时候,就会开启一个通向数据源的设备流,这个文件可以是文件、内存、网络资源。
获取数据:
程序====>硬盘文件
程序====>内存获取
程序====>网络资源
当我们程序要写入数据的时候,开启一个通往目的地的设备流。这个时候我们就可以将数据理解为“流”在管道中进行传输和流动
流的两个特征:
1.含有流质
2.具有方向
这两个特征正好符合计算机系统中数据传输的特征
流来抽象数据传递
方向:硬盘文件到程序(输入流) 程序到硬盘文件(输出流)
在程序中流的分类
java.io包提供了我们操作数据的各种流。流的分类(流质、方向)
-
按方向来分:
1.输入流:从数据源读取到内存。inputStream、Reader对象代表输入流
2.输出流:从内存将数据写入到数据源,outputStream、Writer -
按照类型来分:
1.字节流:传输的时候以byte为最小单位进行传递
2.字符流:传输的时候以char为最小单位来进行传递 -
按照功能来分:
1.节点流:节点流表示从一个特定的数据源读取数据、节点流一般直接操作文件、或者网络等提供的流。他们直接从文件读取数据、将数据直接写入到文件中,也称为低级流
2.处理流:处理流不是直接连接在设备之上,而是建立在其他流之上,通过对数据的处理提供更强大的功能。处理流也称为高级流。
高级流的好处:
在低级流的基础之上,继续扩展和优化了功能。
程序中操作的都是高级流。学习类:InputStream、OutputStream Reader、Writer都是抽象类。使用的是抽象类的子类。
file文件类的操作
java.io包提供的一个类,主要用于管理磁盘里的所有文件或者文件的目录,比如我们可以操作文件的大小、文件的名字、文件的类型,但唯一不能操作的是文件的内容
file类描述的是一个文件或者是文件夹。
该类出现的目的:封装file对象,提供各种文件操作方法,供我们开发过程中直接调用接口可以完成某些特定的功能(创建文件、删除文件、查看文件是否存在)
file.separator //分隔符
创建新的文件夹
File file = new File(路径\文件名) //表示当前文件目录
file.exists() 返回一个boolear值,判断文件是否存在
File file = new File("C:\\software\\fileTest\\day17.txt");
//判断文件是否存在。不存在创建一个
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
file.getAbsolutePath() 返回文件路径
file.getParent() 得到父类路径
file.getName() 返回文件名字
创建一个文件
File file2 = new File(路径\文件名)
file2.mkdir()
file2.isDirectory() //判断当前路径是否是一个文件夹
file2.isFile() //判断是否是文件
file2.delete() //删除空文件夹或文件并返回一个布尔值,判断是否删除成功
file2.list(); // 列出当前文件下所有文件
String[] strs = file2.list();
for (String string : strs) {
System.out.println(string);
}
File[] files = file2.listFiles();
for (File file : files) {
System.out.println(file.getName()+" "+file.length());
}
file2.renameTo() //移动文件
File file2 = new File("C:\\software\\fileTest\\work\\out.txt");
File file3 = new File("C:\\software\\fileTest\\work\\new\\out.txt");
file2.renameTo(file3);
具体流的操作
操作流的步骤:
1.建立流,根据不同类型的数据选择不同的流的操作。
2.操作流,将数据读取到内存,或者将内存数据写入到数据源
3.关闭流,操作结束后,记得将流关闭,释放所有资源。
字节流
字节流以byte作为最小单位,字节流经常用于操作二进制的文件、图片、音频、视频。
-
InputStream:
FileInputStream:对二进制文件进行操作,数据源一般为磁盘,字节流
PipedInputStream:主要针对线程管道
FilterOutputStream:过度流,提供的子类非常重要,缓冲流,数据流
BufferedInputStream:缓冲流
DateInputStream:数据操作流
LineNumberInputStream:表示程序读取哪一行,计数器
ByteArrayOutPutStream:对内存缓冲区的数据进行读写操作,数据源是内存的字节数组
SequenceInputStream:实现两个文件的合并
StringBufferInputStream:用于操作字符串的流
ObjectInputStream:用于操作内存中的对象 -
BufferedInputStream:
缓冲流:缓冲流一个高级流。套在响应节点流基础之上,对读写数据提供缓冲的功能,提高了读写效率,同时还增加了一些额外方法。
缓冲区:
byte[] by = new byte[1024];缓冲区,在内存空间开辟一个缓冲区域,读写现将数据放入缓冲区,减少磁盘的读写
使用缓冲流:
1.减少对磁盘的io操作
2.提高数据读写效率 -
DatetInputStream:
数据流:提供一系列功能,读取的数据转化为一个byte Boolean long float
InputStream in = new FileInputStream(“C:\software\fileTest\b.txt”);
DataInputStream datain = new DataInputStream(in);byte s1 = datain.readByte();
System.out.println(s1);
boolean boo = datain.readBoolean();
System.out.println(boo);
char s3 = datain.readChar();
System.out.println(s3);OutputStream out = new FileOutputStream(“C:\Users\Administrator\Desktop\My_java\day17.txt”);
DataOutputStream dataout = new DataOutputStream(out);
dataout.writeByte(12);
dataout.writeInt(205); -
printWrite:打印流,在system系统输出就已经使用了
OutputStream o = new FileOutputStream(“C:\software\fileTest\k.txt”);
PrintStream out = new PrintStream(o);out.print(true);
out.print(‘a’);
out.print(“xiaowang”);o.close();
out.close();
字符流
字符流是以字符为单位来进行传输的, char java 采用16位Unicode编码表示字符和字符串。字符流分为两种:
字符输入流:Reader
字符输出流:Writer
都是抽象类
字符集:就是规定了某个文字对应的二进制存放方式(编码)和某个二进制值代表了哪个文字(解码)的转换关系
字符编码:
计算机只能存放二进制的数据,我们要让他表示多种多样的数据,我们要对各种字符指定一个数字编码,这种编码就是编码集。
只有编码和解码的方式一致,才能正常显示
计算机中常用的编码:GBK、GB2312、utf-8、unicode编码,前三个支持中文
计算机中只保存字符对应的编码,计算机只需维持字符集清单,当读到这种编码的时候,就与清单中的字符匹配,显示出当前字符。
乱码的原因:编码和解码的编码集不一样。
-
Reader
-InputerStreamReader:转换流,可以将字节流转换为字符流
-FileReader
-BufferReader:缓冲区流 -
Writer
- OutputStreamWriter:字符输出流
- BufferedWriter
如何选择字符流和字节流:
针对文件传输,一般选择字节流,比如:图片、音频、视频
针对文本传输,一般选择字符流
用字符流操作文本内容没问题,整体传输可以传递,用字符来操作文件可能字节丢失,文件打不开
对象的操作
-对象的序列化:将所有的object对象转化为byte为单位的内容传输到目的地(磁盘、网络空间)
-反序列化:将磁盘中的数据以byte为单位读取,转化为object对象放入内存。
创建对象:new 克隆 反序列化
序列化规范:
1.你要序列化的对象必须要实现Serializable接口,如果对象没有实现接口,序列化的时候抛出没有实现接口的异常。
2.静态变量和成员方法不可序列化
3.一个类要被序列化,该类可应用的对象也应该是可被序列化的,否则整个序列化的过程将失败
4.声明transient关键字可以控制当前属性不被序列化
-ObjectInputStream
(1)创建一个文件对象
File file = new File("C:\\software\\fileTest\\object.txt")
;
(2)创建流
ObjectInputStream objin = new ObjectInputStream(new FileInputStream(file));
(3)操作对象:反序列化
try {
Object obj = objin.readObject();
StudentBean stu = (StudentBean) obj;
System.out.println(stu);
System.out.println(stu.age);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
(4)关闭
objin.close();
-ObjectOutputStream
(1)创建一个文件对象
File file = new File("C:\\software\\fileTest\\object.txt");
(2)创建一个流
OutputStream o = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(o);
(3)操作对象,写入到文件
ClassBean cb = new ClassBean(1,"wn46");
StudentBean stu = new StudentBean(1, "xiaowang",cb);
out.writeObject(stu);
(4)关闭流
out.close();
重复传输默认将以前数据覆盖,导致以前数据丢失
多对象操作
-
序列化
(1)创建一个文件对象 File file = new File("C:\\software\\fileTest\\object1.txt"); (2)创建一个流 调用构造的时候,传递了一个boolean值 true表示:追加信息到文本, false覆盖 FileOutputStream o = null; ObjectOutputStream out =null; if(file.exists()){ long index = 0; o = new FileOutputStream(file,true); out = new ObjectOutputStream(o); //每次写对象到文件的时候,都会默认创建一个头信息,StreamHeader有4个字节所以减去 index = o.getChannel().position()-4; o.getChannel().truncate(index); out.writeObject(stu); }else{ o = new FileOutputStream(file); out = new ObjectOutputStream(o); out.writeObject(stu); }
//(3)操作对象,写入到文件
//(4)关闭流
out.close(); -
反序列化
//(1)创建一个文件对象 File file = new File("C:\\software\\fileTest\\object1.txt"); FileInputStream filein = new FileInputStream(file); //(2)创建流 ObjectInputStream objin = new ObjectInputStream(filein); (3)操作对象:反序列化 try { while(filein.available()>0){ Object obj = objin.readObject(); StudentBean stu = (StudentBean) obj; System.out.println(stu); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } //(4)关闭 objin.close();