I/O流的理解概述:
- I/O流:数据(文件,图片,视频等)以字节的形式存储,以流的形式在不同数据存储体间传输,以内存为基准可以将流的方向分为
输入input
和输出output
,即流向内存是输入流,流出内存的输出流;按数据传输单位可以将流分为字节流,字符流。 - 字节流与字符流:若文本文件含有多字节组成的字符时,应使用字符流读取文本。若使用字节流读取可能不会显示完整的字符,因为字节流每次只读取一个字节,只是完整字符的一部分。
具体的:Java中的String类型默认就把字符以Unicode规则编码(一个字符对应两个字节)而后存储在内存中,字符流的读取单位就是一个Unicode码元。 - java.io包中按照流划分角度的组合封装了四个顶级父类(选择抽象类而不是接口是因为若一个类同时实现输出流,输入流两个接口就会出错,而继承体系只能单继承),完成I/O操作,即输入、输出操作。输入也叫做读取数据,即从其他存储体对象读取数据到流中,流传输到内存中;输出也叫做作写出数据,即从内存写出数据到流中,流传输到其他存储体对象中。流对象在创建的时候就必须明确指向内存之外的另一存储体。
输入流 输出流 字节流 字节输入流InputStream 字节输出流OutputStream 字符流 字符输入流Reader 字符输出流Writer - 写出数据的原理:以内存-->硬盘为例
java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用写数据的方法-->把数据从内存写出到硬盘文件中(待写的数据就是写方法的参数) - 读取数据的原理:以硬盘-->内存为例
java程序-->JVM-->OS-->OS读取数据的方法-->读取文件(硬盘-->内存)
FileStream的理解概述:
-
以文件作为与内存进行数据传输的另一存储体,对应四种顶级父类分别有子类FileOutputStream,FileInputStream,FileReader,FileWriter。
FileStream的使用概述:
- 四种顶级父类都定义了所有子类共有的基本方法,子类只需要创建对象,调用父类中的基本方法。
抽象类java.io.OutputStream中子类共有的成员方法:
-public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
-public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
-public void write(byte[] b):将字节数组从内存写出此输出流指向的文件。
-public void write(byte[] b, int off, int len) :把字节数组的一部分从内存写出到此输出流指向的文件。
int off:数组的开始索引
int len:写几个字节
-public abstract void write(int b) :将指定的字节从内存写出道此输出流指向的文件。int类型为4字节,即32个bit位,此处只写低8位
java.io.FileOutputStream 构造方法:
-public FileOutputStream(File file) :创建文件输出流对象并指向指定文件 即File对象。
-public FileOutputStream(String name) : 创建文件输出流对象并指向指定路径的文件。
-public FileOutputStream(File file, boolean append) : 创建文件输出流指向指定文件,并设置是否清空原有内容。
-public FileOutputStream(String name, boolean append) : 创建文件输出流指向指定路径的文件,并设置是否清空原有内容。
抽象类java.io.InputStream中子类共有的成员方法:
-public abstract int read()从输入流中读取数据的下一个字节。
-public int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
-public void close() 关闭此输入流并释放与该流关联的所有系统资源。
FileInputStream的构造方法:
-public FileInputStream(String name)通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
-public FileInputStream(File file) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
-public
抽象类 java.io.Writer中子类共有的成员方法:
-void write(int c) 写入单个字符。
-void write(char[] cbuf)写入字符数组。
-abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
-void write(String str)写入字符串。
-void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
-void flush()刷新该流的缓冲。
-void close() 关闭此流,但要先刷新它。
FileWriter的构造方法:
-FileWriter(File file): 根据给定的 File 对象构造一个 FileWriter 对象。
-FileWriter(String fileName): 根据给定的文件名构造一个 FileWriter 对象。
-FileWriter(String fileName, boolean append)
-FileWriter(File file, boolean append)
参数:
String fileName,File file:写入数据的目的地
boolean append:续写开关 true:不会创建新的文件覆盖源文件,可以续写; false:创建新的文件覆盖源文件
抽象类 java.io.Reader中子类共有的成员方法:
-int read() 读取单个字符并返回。
-int read(char[] cbuf)一次读取多个字符,将字符读入数组。
-void close() 关闭该流并释放与之关联的所有资源。
FileReader的构造方法:
-FileReader(String fileName)
-FileReader(File file)
参数:读取文件的数据源
String fileName:文件的路径
File file:一个文件
FileOutputStream的测试代码(整体阅读,局部运行):
/**运行前提:
*1. import...
*/
public class FileOutputStreamTest throws IOException {
public static void main(String[] args) throws IOException {
show1();
show2();
}
/**show1():通过FileOutputStream将内存中的内容写进硬盘的文件里
*1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
*2.调用FileOutputStream对象中的方法write,把数据写入到文件中
*3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
*/
static void show1() throws IOException {
//1.
/* 构造方法的作用:
1.创建一个FileOutputStream对象
2.会根据构造方法中传递的文件/文件路径,创建一个空的文件,注意不会创建文件夹
3.会把FileOutputStream对象指向创建好的文件
*/
FileOutputStream fos = new FileOutputStream("MyTest\\a.txt");//创建一个向指定文件路径中写入数据的输出文件流
//FileOutputStream fos = new FileOutputStream(new File("MyTest\\b.txt")); 创建一个向指定 File 对象表示的文件(注意:不是文件路径)中写入数据的文件输出流。
//2.
//写数据到硬盘文件时,会把10进制的整数转换为二进制存储(8个bit位),但是记事本打开文件时会查询编码表将字节转换为字符表示,0-127会查询ASCII表,其他值会查询系统默认码表(中文系统GBK)
fos.write(97);//a
//
//white(int)只能写入一个字节,若在文件中显示100,需要写3个字节
fos.write(49);//1
fos.write(48);//0
fos.write(48);//0
//
/*
一次写多个字节:
如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
*/
//使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率,建议开发中使用
byte[] bytes = {65,66,67,68,69};//ABCDE
//byte[] bytes = {-65,-66,-67,68,69};//烤紻E
fos.write(bytes);
//
fos.write(bytes,1,2);//BC,从bytes数组索引为1的位置写入2个字节到文件中
//
/*
写入字符的方法:可以使用String类中的方法把字符串,转换为字节数组
byte[] getBytes() 把字符串转换为字节数组
*/
byte[] bytes2 = "你好".getBytes();
System.out.println(Arrays.toString(bytes2));//[-28, -67, -96, -27, -91, -67]
fos.write(bytes2);
//3.
fos.close();
}
/**show2():
*1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地和追加写开关
*2.调用FileOutputStream对象中的方法write,把数据写入到文件中
*3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
*/
static void show2() throws IOException {
//1.
FileOutputStream fos = new FileOutputStream("MyTest\\c.txt",true); //true:追加数据
//FileOutputStream fos = new FileOutputStream("MyTest\\c.txt",false); false:清空原有数据
//2.
for (int i = 1; i <=10 ; i++) {
fos.write("你好".getBytes());
//
//windows:\r\n 为换行符号,转成byte[]数组写
fos.write("\r\n".getBytes());
}
//3.流操作完毕后,必须释放系统资源,调用close方法
fos.close();
}
}
FileInputStream的测试代码(整体阅读,局部运行):
/**整体阅读,局部运行
* 1.import ...
* 2.项目文件夹里有MyTest//c.txt文件
*/
public class InputStreamTest {
public static void main(String[] args) throws IOException {
show1();
show2();
}
/**show1():从文件中读取单个字节
* 1.创建FileInputStream对象,构造方法中绑定要读取的数据源
* 2.使用FileInputStream对象中的方法read,读取文件
* 3.释放资源
*/
static void show1() throws IOException {
//1.
/* 构造方法的作用:
1.会创建一个FileInputStream对象
2.会把FileInputStream对象指向构造方法中要读取的文件的第一个字节
*/
FileInputStream fis = new FileInputStream("MyTest\\c.txt"); //文件内容为abc
//FileInputStream fis = new FileInputStream(new File("MyTest\\c.txt"));
//2.int read()通过JVM,再通过OS,读取文件中的指针指向的字节并提升到int返回,连续读取时指针依次向后移,读取到文件的末尾返回-1
int len = fis.read();
System.out.println(len);//97
len = fis.read();
System.out.println(len);// 98
len = fis.read();
System.out.println(len);//99
len = fis.read();
System.out.println(len);//-1
/*
int len = 0; //记录读取到的字节
while((len = fis.read())!=-1){
System.out.print((char)len);//abc
}
*/
//3.
fis.close();
}
/**show2():从文件中读取字节数组
*1.创建FileInputStream对象,构造方法中绑定要读取的数据源
*2.使用FileInputStream对象中的方法read读取文件
*3.关闭资源
*/
public void show2() throws IOException {
//1.
FileInputStream fis = new FileInputStream("MyTest\\b.txt");//文件内容为ABCDE
//2.
//int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
byte[] bytes = new byte[2]; // byte[]起到缓冲作用,存储每次读取到的多个字节,数组的长度一把定义为1024(1kb)或者1024的整数倍
//
//不同于读取单个字节int len记录每次读取的有效字节个数
int len = fis.read(bytes);
System.out.println(len);//2
//System.out.println(Arrays.toString(bytes));//[65, 66]
/
//String(byte[] bytes) :把字节数组转换为字符串
System.out.println(new String(bytes));//AB
len = fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//CD
len = fis.read(bytes);
System.out.println(len);//1
//
//String(byte[] bytes, int offset, int length) 把字节数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数
System.out.println(new String(bytes,0,len));//E
//System.out.println(new String(bytes)); ED 错于当缓冲数组容量大于剩余字节时,上次读取的数据没有被完全替换而重复读取,所以要通过 len ,获取有效的字节.
len = fis.read(bytes);
System.out.println(len);//-1
/*
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes))!=-1){
//
//当数组容量大于读取内容时,直接转换成字符串会生成大量空格,所以只转换有效字节
System.out.println(new String(bytes,0,len));
}
*/
//3.
fis.close();
}
}
FileWrite的测试代码(整体阅读,局部运行):
/**运行前提:
*1.import...
*2.项目文件夹下备有作参数的文件夹,文件
*/
public class WriterTest {
public static void main(String[] args) throws IOException {
show1();
}
/**show1():
* 1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
* 2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
* 3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
* 4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
*/
static void show1() throws IOException{
//1.
/*
构造方法的作用:
1.会创建一个FileWriter对象
2.会根据构造方法中传递的文件/文件的路径,创建文件
3.会把FileWriter对象指向创建好的文件
*/
FileWriter fw = new FileWriter("MyTest\\e.txt");
//FileWriter fw = new FileWriter(new File("MyTest\\e.txt"));
//FileWriter("MyTest\\e.txt", true); append:true 不会创建新的文件覆盖源文件
//FileWriter("MyTest\\e.txt", false); append:false 会创建新的文件覆盖源文件
//2.
//write(int c)写入单个字符。
fw.write(97);
fw.write("\r\n"); //windows换行符:\r\n
//write(char[] cbuf)写入字符数组。
char[] cs = {'a','b','c','d','e'};
fw.write(cs);//abcde
fw.write("\r\n");
//void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
fw.write(cs,1,3);//bcd
fw.write("\r\n");
//void write(String str)写入字符串。
fw.write("你好世界");//你好世界
fw.write("\r\n");
//void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
fw.write("你好世界",0,2);//你好
fw.write("\r\n");
//3. 刷新之后流可以继续使用
fw.flush();
fw.write(98);
//4.先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
fw.close();
fw.write(99);//IOException: Stream closed
}
}
FilerReader的测试代码(整体阅读,局部运行):
public class ReaderTest {
public static void main(String[] args) throws IOException {
show1();
}
/**show1():
* 1.创建FileReader对象,构造方法中绑定要读取的数据源
* 2.使用FileReader对象中的方法read读取文件
* 3.释放资源
*/
static void show1(){
//1.
/*
FileReader构造方法的作用:
1.创建一个FileReader对象
2.会把FileReader对象指向要读取的文件
*/
FileReader fr = new FileReader("MyTest\\c.txt");
//FileReader fr = new FileReader(new File("MyTest\\c.txt"));
//2.
//int read() 读取单个字符并返回。
int len = 0;
while((len = fr.read())!=-1){
System.out.print((char)len);
}
//int read(char[] cbuf)一次读取多个字符,将字符读入数组。
char[] cs = new char[1024];//存储读取到的多个字符
int len = 0;//记录的是每次读取的有效字符个数
while((len = fr.read(cs))!=-1){
System.out.println(new String(cs,0,len));
}
//3.
fr.close();
}
}