I/O 流的一些自我总结

在这里,我自己总结一下我学习Java的I/O的一些总结
首先,介绍一下I/O流的概念:

 IO流用来处理设备之间的数据传输
1. Java对数据的操作是通过流的方式
2. Java用于操作流的类都在IO包中
3. 流按流向分为两种:输入流,输出流。
4. 流按操作类型分为两种:
4.1.字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
4.2.字符流 : 字符流只能操作纯字符数据,比较方便。

I/O流分为字符流和字节流
字节流的输入和输出:InputStream , OutputStream
字符流的输入和输出:Reader ,Writer
(PS:字符流不能用来复制文件,因为字符流每次读入都是一个字符,经过转码可能会出现乱码,因为一个字符等于两个字节,字符码只用来读文件或者写文件)

伪代码(复制文件)
Class{
FileInputStream fis = new InputStream("xxx.txt");  //读xxx.txt文件
FileOutputStream fos = new OutputStream("yyy.txt");  //写文件到yyy.txt文件中

int a=0;
while( (a=fis.read()!=-1) ){           //由于当读文件读到-1的时候就读完,每次赋值给a进行判断
     	fos.write(a);
}
fis.close();
fos.close();



那么一个字节为什么a要用int类型,返回一个int类型而不是byte类型呢?
答:因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型

以上是基本代码,最基础,但是效率很差,需要一个一个地区遍历,一个一个地去传入文件,所以可以优化,设置一个数组,先读取足够多的一组数据,然后再一次写到文件中去,这样的效率会加快,而数组的大小是有要求的,必须是1024的倍数。

伪代码:
FileInputStream fis = new FileInputStream("致青春.mp3");
		FileOutputStream fos = new FileOutputStream("copy.mp3");
		int len;
		byte[] arr = new byte[1024 * 8];					//自定义字节数组
		
		while((len = fis.read(arr)) != -1) {
			//fos.write(arr);
			fos.write(arr, 0, len);							//写出字节数组写出有效个字节个数
		}
		
		fis.close();
		fos.close();




那么每一次都设置一个数组做起来就会很麻烦,所以Java有BufferedInputStream和BufferedOutputStream方法来封装InputStream和OutputStream这两个输入输出方法,使得文件先读进缓冲区,然后在缓冲区读取足够多字节后再进入内存,然后进入写的缓冲区,一次性写进文件中。而BufferedInputStream内置了一个缓冲区,会一次性从文件中读取8192个字节,即是8*1024个字节,程序再次读文件时就不用再次去找文件了,直接从缓冲区中读取。BufferedOutputStream也是同样的道理,程序向流写出字节时,不会直接写进文件,而是先写到缓冲区,当缓冲区写满再一次性写到文件中。
以下是伪代码:
   
  class{           
		FileInputStream fis = new FileInputStream("陀飞轮.mp3");			//创建文件输入流对象,关联致青春.mp3
		BufferedInputStream bis = new BufferedInputStream(fis);			//创建缓冲区对fis装饰
		FileOutputStream fos = new FileOutputStream("copy.mp3");		//创建输出流对象,关联copy.mp3
		BufferedOutputStream bos = new BufferedOutputStream(fos);		//创建缓冲区对fos装饰
		
		int b;
		while((b = bis.read()) != -1) {		
			bos.write(b);
		}
		
		bis.close();						//只关装饰后的对象即可
		bos.close();
}

 还有一种是定义一个小数组,那种不用经过缓冲区,对于没那么大的文件来说,定义小数组会更快,但对于大文件来说,Buffered的用法会更快。 
 


刷新缓冲区的方法:
close()会直接刷新缓冲区再关闭输入输出流
fluse()会直接刷新缓冲区,但没有关闭输入输出流,还能继续输入和输出

流的标准处理异常:
		try(
			FileInputStream fis = new FileInputStream("aaa.txt");
			FileOutputStream fos = new FileOutputStream("bbb.txt");
			MyClose mc = new MyClose();
		){
			int b;
			while((b = fis.read()) != -1) {
				fos.write(b);
			}
		}

以上就是字节流我所理解到的知识点
华丽丽的分割线
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以下是字符流的知识点:
字符流的输入输出流是Reader和Writer,同样以文件为例子
字符流读文件:
	FileReader fr = new FileReader("aaa.txt");				//创建输入流对象,关联aaa.txt
	int ch;
	while((ch = fr.read()) != -1) {							//将读到的字符赋值给ch
		System.out.println((char)ch);						//将读到的字符强转后打印
	}
	
	fr.close();

字符流也可以拷贝文本文件, 但不推荐使用. 因为读取时会把字节转为字符, 写出时还要把字符转回字节.
* 程序需要读取一段文本, 或者需要写出一段文本的时候可以使用字符流
* 读取的时候是按照字符的大小读取的,不会出现半个中文
* 写出的时候可以直接将字符串写出,不用转换为字节数组

所以字符流也不能能拷贝非纯文本的文件。




IO流的readLine()和newLine()方法。
BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"

newLine()是换行
readLine()是读取一行数据

newLine()是换行后,就可以使用readLine()来一行行读取数据



代码:
	BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));
	BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt"));
	String line;
	while((line = br.readLine()) != null) {
		bw.write(line);
		//bw.write("\r\n");					//只支持windows系统
		bw.newLine();						//跨平台的
	}
	
	br.close();
	bw.close(); 

IO流(LineNumberReader) 
* LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号
* 调用getLineNumber()方法可以获取当前行号
* 调用setLineNumber()方法可以设置当前行号

LineNumberReader lnr = new LineNumberReader(new FileReader("aaa.txt"));
		String line;
		lnr.setLineNumber(100);									//设置行号
		while((line = lnr.readLine()) != null) {
			System.out.println(lnr.getLineNumber() + ":" + line);//获取行号
		}
		
		lnr.close();

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以下是序列流的个人理解:
序列流可以把多个字节输入流整合成一个, 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.

*SequenceInputStream(InputStream, InputStream)
	 
			FileInputStream fis1 = new FileInputStream("a.txt");			//创建输入流对象,关联a.txt
			FileInputStream fis2 = new FileInputStream("b.txt");			//创建输入流对象,关联b.txt
			SequenceInputStream sis = new SequenceInputStream(fis1, fis2);		//将两个流整合成一个流
			FileOutputStream fos = new FileOutputStream("c.txt");			//创建输出流对象,关联c.txt
			
			int b;
			while((b = sis.read()) != -1) {						//用整合后的读
				fos.write(b);							//写到指定文件上
			}
			
			sis.close();
			fos.close();


内存输出流(ByteArrayOutputStream)
	FileInputStream fis = new FileInputStream("a.txt");
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	int b;
	while((b = fis.read()) != -1) {
				baos.write(b);
			}
			
	//byte[] newArr = baos.toByteArray();	//将内存缓冲区中所有的字节存储在newArr中
	//System.out.println(new String(newArr));
	System.out.println(baos);
	fis.close();

打印流
1.该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式
2.System.out就是一个PrintStream, 其默认向控制台输出信息
        PrintStream ps = System.out;
	ps.println(97);		//其实底层用的是Integer.toString(x),将x转换为数字字符串打印
	ps.println("xxx");
	ps.println(new Person("张三", 23));
	Person p = null;
	ps.println(p);		//如果是null,就返回null,如果不是null,就调用对象的toString()
使用方法:
      PrintWriter pw = new PrintWriter(new FileOutputStream("g.txt"), true);
      pw.write(97);
      pw.print("大家好");
      pw.println("你好");           //自动刷出,只针对的是println方法
      pw.close();



IO流(标准输入输出流概述和输出语句)
1.什么是标准输入输出流(掌握)
System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据
System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
2.修改标准输入输出流(了解)
修改输入流: System.setIn(InputStream)
修改输出流: System.setOut(PrintStream)
 
	System.setIn(new FileInputStream("a.txt"));	//修改标准输入流
	System.setOut(new PrintStream("b.txt"));				//修改标准输出流
			
	InputStream in = System.in;								//获取标准输入流
	PrintStream ps = System.out;							//获取标准输出流
	int b;
	while((b = in.read()) != -1) {							//从a.txt上读取数据
		ps.write(b);										//将数据写到b.txt上
	}
			
	in.close();
	ps.close();


猜你喜欢

转载自blog.csdn.net/m0_38012174/article/details/77184787