1:IO介绍
在前面学习的程序中数据最终都内存中,变量,int a = 10; 数组、字符串、集合,这些容器都可以存放数据,但是它们把数据都存放在内存中,一旦程序停止运行,JVM退出。那么给JVM分配的内存空间就消失了,在整个程序中的数据就没有了。
内存属于临时存储设备,断电、程序运行结束,内存释放,数据就消失。
持久化存储设备:数据可以这类设备上长久的保存。硬盘、U盘、光盘、磁带、软盘、云盘等。这些设备都可以长久的保存数据,当需要数据的时候,可以到这些设备上获取数据。
IO技术:把程序中的数据最终输出到持久设备上。或者从持久设备读取已经存在的数据,最后给我们读取到程序中。
IO:input 输入 读操作
output输出 写操作
2:file类介绍
需要把数据持久的保存起来,最终都要以文件的形式存储在持久设备上。如果持久设备上文件太多如何管理?就会使用文件夹来管理文件或者文件夹。
在学习IO技术之前,需要了解Java是如何针对文件和文件夹这类事物做封装的。
在Java中使用File 这个类来描述持久设备上的文件或者文件夹。
文件:是用来保存真实的数据的。
文件夹:管理文件和文件夹。
File类常用的构造方法有2个,构造方法可以把对应的文件或者文件夹来封装成一个File对象。File没有空参数的构造方法。
常用的构造方法:
1、File(String pathname)
把一个字符串描述的文件或者文件夹封装成File对象。 File类的构造方法会把指定的内容封装成File对象,
2、File(String parent, String child)
可以把一个文件或者文件夹的父目录单独分离出来,然后在结合当前的子目录一起封装成File对象
3:file常用方法
package Week5ClassFir;
import java.io.File;
public class DemoFile {
public static void main(String[] args) {
//方法名称 -说明
//boolean exists() -判断文件或目录是否存在
//boolean isFile( ) -判断是否是文件
//boolean isDirectory() -判断是否是目录
//String getPath() -返回此对象表示的文件的相对路径名
//String getAbsolutePath() -返回此对象表示的文件的绝对路径名
// String getName() -返回此对象表示的文件或目录的名称
//boolean delete() -删除此对象指定的文件或目录
//boolean createNewFile() -创建名称的空文件,不创建文件夹
//long length() -返回文件的长度,单位为字节,如果文件不存在,则返回OL
File file=new File("C:\\Users\\15727\\Desktop\\KJ-12\\新建文件夹\\Hello.txt");
boolean b1=file.exists();
boolean b2=file.isFile();
boolean b3=file.isDirectory();
String s1=file.getPath();
String s2=file.getAbsolutePath();
String s3=file.getName();
boolean b4=file.delete();
File f = null;
try {
f = new File("test.txt");
boolean b5=f.createNewFile();
System.out.println("创建名称的空文件,不创建文件夹:"+b5);
}catch (Exception e){
e.printStackTrace();
}
Long l1=file.length();
System.out.println("判断文件或目录是否存在:"+b1);
System.out.println("判断是否是文件:"+b2);
System.out.println("判断是否是目录:"+b3);
System.out.println("返回此对象表示的文件的相对路径名:"+s1);
System.out.println("返回此对象表示的文件的绝对路径名:"+s2);
System.out.println("返回此对象表示的文件或目录的名称:"+s3);
System.out.println("删除此对象指定的文件或目录:"+b4);
System.out.println("返回文件的长度,单位为字节,如果文件不存在,则返回OL:"+l1);
}
}
4:字节流
File类是描述文件和文件夹的,并且其中定义的方法都是围绕文件和文件夹的操作展开的。
但是File类有缺陷,它无法去获取一个文件中的数据。
如果我们在程序中要读取文件中存放的具体的数据,或者给文件中写数据,这时必须使用Java中提供的另外一套机制来读取,
这套机制就是IO流技术。I: InputStream ; O:OutputStream
流的分类:
使用流的目的是把程序中的数据写持久设备上,或者从持久设备上读取数据,在写或者读之前,先要让这个流和持久设备之间建立
一个读或者写的通道,只有有了这个通道之后才能在这个通道中开始读写数据。
FileInputStream
FileOutputStream
AbcInputStream
AbcOutputStream
1:InputStream
fileInputStream是inputStream常用子类。
fileInputStream流被称为文件字节输入流,意思指对文件数据以字节的形式进行读取操作如读取图片视频等.
常用的构造方法有:FileInputStream(File file);FileInputStream( String path )
常用的方法有:
int read( ): 这个方法被调用一次,它运行一次,会从底层读取一个字节数据,当把这个字节读取完成之后,在文件中的隐式光标自动的移动到第一个字节和第二个字节之间。返回的数据是这个字节数据转成int值,当读取到文件的末位时,会返回-1.因此在使用read方法读取数据的时候,通过判断读取的数据是否是-1来判断是否把文件中的数据已经全部读取完成。
int read(byte[] b):这个方法每执行一次,就会从底层读取多个字节数据,把读取到的字节数据存储在byte数组中。返回的int值,是表示当前到底从底层读取了几个字节数据。 即就是给byte数组中存储了几个字节数据。如果读取到文件末位会返回-1。
int read(byte[] b,int off,int len):off从哪里开始,读多少
void close( ):关闭流,在使用完成之后一定要关闭流
2:字节读取文件模板
1、一次读取一个字节的模版代码
1、先创建流对象和文件进行关联
FileInputStream fis = new FileInputStream("文件");
2、定义变量,用来记录从底层文件中读取到的那个字节数据
int ch = 0;
3、定义循环开始从文件中读取数据
while( ( ch = fis.read() )!=-1 ){
//处理读取到的数据,数据存储在ch空间中
}
4、关闭流对象
fis.close();
2、一次读取多个字节数据模版代码
1、先创建流对象和文件进行关联
FileInputStream fis = new FileInputStream("文件");
2、定义数组,用来存储从底层读取的多个字节数据,一般都是1024的整数倍
byte[] buf = new byte[1024];
3、定义变量,用来记录到底从底层读取了多个字节数据,
int len = 0;
4、使用循环从底层开始读取数据
while( ( len = fis.read( buf ) )!=-1 ){
//处理读取到的数据,数据存储在buf数组中,buf中共计存储了len个字节数据,并不一定把buf存满
}
5、关闭流对象
fis.close();
3:OutputStream
数据在持久设备上都以二进制保存,字节数据,因此Java给我们提供了专门操作持久设备上的流对象,字节流。
OutputStream:专门用来操作字节数据的字节输出流对象。是所有字节输出流的超类,并且是个抽象类,不能直接创建对象。
写的方法:
write(int b); 把字节数据直接写到持久设备上
write( byte[] buf ); 把字节数组中的数据写到持久设备上。
write( byte[] buf , int off , int len ) 把buf字节数组中的数据从off下标开始共计写出len个字节数据
close() ; 关闭Java程序和外围设备直接的连接通道。
在OutputStream类下有直接的子类FileOutputStream:
FileOutputStream:是专门用于把程序中的数据写到指定的文件中的输出流对象,这个流主要是用来写字节数据的。
FileOutputStream的构造方法:
FileOutputStream(File file)在创建输出流对象的时候,指定一个文件对象,用于把数据写到指定的这个文件中
FileOutputStream(String pathName) 在创建输出流对象的时候,把这个字符串当前一个具体的文件位置,然后把数据写到这个文件中
在使用输出流的时候,如果指定的文件不存在,会自动创建这个文件对象,如果文件存在,会创建一个新的把原来的文件覆盖掉。
子类FileOutputStream常用的构造方法
FileOutputStream (File file)
FileOutputStream(String name)
FileOutputStream(String name,boolean append)
注意:
前面两个构造方法如果指定的文件不存在,会自动创建这个文件对象,如果文件存在,会创建一个新的把原来的文件覆盖掉。
第三个构造方法写数据时,当文件不存在同样会新建一个文件,如果文件存在了,第二个参数表示是否追加,false表示不追加(默认),和其他的两个构造方法结果一致,为true时,表示追加,在原来内容的基础上新增新的内容。
5:字符流
Java给我们提供专门用于操作字符数据的流对象
字符输入流:Reader
字符输出流:Writer
1:Reader
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。
多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
Reader类常用方法
int read( ):执行一次,会得到一个字符数据,如果读取到文件末尾,返回的-1
int read(char[] c):执行一次,会从底层读取多个字符数据,存储在字符数组中,返回本次读取的字符数据个数,
如果读取到文件末位,返回-1
read(char[] c,int off,int len),将读取到的数据存储在数组中,从off开始,到len结束
void close( )
子类InputStreamReader常用的构造方法,它又称为转换流
InputStreamReader(InputStream in)
InputStreamReader(InputStream in,String charsetName)
FileReader类是InputStreamReader的子类
FileReader(File file)
FileReader(String name)
2:字符读取文件模板
字符输入流读取数据的模版代码:
1、一次读取一个字符数据:
//定义字符输入流对象和文件进行关联
FileReader fr = new FileReader("文件");
//定义变量,存储读取到的字符数据
int ch = 0;
//使用循环读取数据
while( ( ch = fr.read() )!=-1 ){
//处理读取到的单个字符数据,数据在ch中保存着
}
//关闭流对象
fr.close();
2、一次读取多个字符数据
//定义字符输入流对象和文件进行关联
FileReader fr = new FileReader("文件");
//定义字符数组,用来存储一次读取到的多个字符数据
char[] buf = new char[1024];
//定义变量,记录每次读取到字符个数
int len = 0;
//使用循环读取数据
while( ( len = fr.read( buf ) )!=-1 ){
//处理读取到的数据,数据保存在buf中,buf中共计保存了len个字符数据
}
//关流
fr.close();
3:BufferedReader
BufferedReader提高字符流读取文本文件,有一个独有的方法readLine(),又称高效流,带有缓冲区的流
当所有文件信息多获取完成时候,readLine()方法将返回null.
注意:文档中有空行,读取的时候不是null, 而是空内容
BufferedReader常用的构造方法
BufferedReader(Reader in),需要接受一个字符流
如果读取文件中出现中文乱码问题时,可以考虑指定编码,原则如下:
FileInputStream fis=new FileInputStream("c:\\myDoc\\hello.txt");
//使用InputStreamReader并设置编码格式
InputStreamReader fr=new InputStreamReader(fis,"UTF-8");
BufferedReader br=new BufferedReader(fr);
4:Writer
Writer类常用方法
write(String str) : 写一个字符串
write(String str,int off,int len): 把cbuf中的字符数据从off开始,共计写len个
void close(): 关闭流
void flush() : 刷新
子类OutputStreamWriter常用的构造方法
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charsetName)
FileWriter类是OutputStreamWriter的子类
FileWriter (File file)
FileWriter (String name)
注意:
用字符输出流写出数据的时候:
1、其实数据不是直接写到文件中,而是把字节数据存储在缓冲区中。如果这时字符输出流的缓冲区没有写满,或者我们没有调用flush方法,或没有关闭流对象,在程序结束之前,数据依然在缓冲区中,不会被写到文件中。所以要求,在关闭流之前一定要做刷新操作。
2、字符输出流(FileWriter)关联的文件如果不存在,会在指定的位置创建,如果文件存在,在创建流对象的时候,没有指定的true值,这时会创建新的文件覆盖原来的文件。
flush和close什么区别:
flush是把缓冲区的数据刷出到文件中,没有关闭流和文件之间的关联,在刷新之后,依然可以使用流对象继续给文件中写数据。
close方法在关闭流之前会先调用flush把缓冲区中的数据写底层文件中,然后把流和文件的关联关系断开。
一旦调用的close方法,流就已经被关闭了,就无法在使用当前这个流对象写数据。
5:BufferedWriter
使用FileWriter类与BufferedWriter类可以提高字符流写文本文件的效率
BufferedWriter常用的构造方法
BufferedWriter(Writer out)
6:流的总结:
字节流:2类
字节输入流:
InputStream:它是字节输入流的超类,它中定义字节输入流的基本操作方法:
close();
read() 一次读取一个字节数据
read( byte[] buf ) 一次读取多个字节数据,存储在buf中,然会给buf中读取的字节个数
FileInputStream:专门用来读取文件中的字节数据的文件字节输入流对象
创建这个类的对象,读取文件中的数据
模版代码:
- 一次读取一个字节
FileInputStream fis = new FileInputStream(“文件”);
int ch = 0;
while( ( ch = fis.read() )!=-1 ){
处理读取到的数据,数据在ch中
}
fis.close();
2、一次读取多个字节数据
FileInputStream fis = new FileInputStream(“文件”);
byte[] buf = new byte[1024];
int len = 0;
while( ( len = fis.read( buf ) )!=-1 ){
处理数据,数据在buf中,共计有len个
}
fis.close() ;
字节输出流:
OutputStream:字节输出流的超类,它中定义的基本的输出字节数据的操作
close();
write( int b ) 写出一个字节数据,注意只能把这个int数据中的最低1个字节数据写出去
write(byte[] buf ) 把字节数组中的所有数据写到文件中
write( byte[] buf ,int off ,int len ) 把字节数组中的数据从off开始,共计写len个
FileOutputStream:它是专门用来给文件中写字节数据的流对象。使用输出流写数据的时候,如果对应的文件不存在会新建一个文件,如果文件存在,在创建对象的时候,没有指定true值,就会继续创建新的文件,覆盖原来的文件。
一般会在读的while循环中使用写的功能,往出把读取到的数据写出去。
字符流:2类
字符输入流:
Reader:是所有字符输入流的超类。
close()
read() 一次读取一个字符数据,但返回的字符数据的编码值
read( char[] buf ) 一次读取多个字符数据,把数据存储在buf中,返回读取的字符个数
FileReader:专门用于读取字符文件字符输入流对象,它内部使用本地默认的编码表(GBK)
字符输出流:
Writer:是所有字符输出流的超类
close();
write( int b ) 写出一个字符数据 write(‘a’) 这里会把这个a转成97,再写出去
字符数据和int数据在一定的范围内可以互相赋值
int x = ‘A’;
char ch = 99;
write( char[] buf )把buf数组中的数据全部写出去
write( chr[] buf , int off ,int len) 把buf中的数据从off开始共计写len个
write( String s ) 把一个字符串写出去
FileWriter:专门用于给字符文件中写字符数据的便捷类,它的底层使用的默认的编码表和默认的缓冲区。
7:DataInputStream
在IO包中提供了两个与平台无关的数据操作流
数据输出流:DataOutputStream
数据输入流:DataInputStream
其使用方法和字节流类似。
DataInputStream类
FilterInputStream的子类
与FileInputStream类结合使用读取二进制文件
构造方法:DataInputStream(InputStream in)
DataOutputStream类
FilterOutputStream的子类
与FileOutputStream类结合使用写二进制文件
构造方法:DataOutputStream(OutputStream out)
8:序列化和反序列化
序列化是一个用于将对象状态转换为字节流的过程。需要使用对象输出流ObjectOutputStream。
简单的说:我们使用new关键字创建在内存中的对象,包括对象中的所有数据,持久性的保存到硬盘上,通常是文件中,
对象 ---》 文件
反序列化则是从特定的流中获取数据重新构建对象的过程 。需要使用对象输入流ObjectInputStream。
保存在文件中的对象通过反序列化的手段从新加载到内存中
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
注意:
1:序列化和反序列化都是基于二进制流的,也就是说,在信息转化为二进制存储在文件中之后,用文本编辑器打开查看的话,肯定是会出现乱码的。只有通过反序列化才能将存储的二进制读取出来,然后正常显示在控制台上。
2:如果一个对象要实现序列化的话,则这个类必须要实现一个序列化的接口
实现序列化:序列化是写的过程
实现反序列化:反序列化是读的过程