java之I/O
引入
- I/O问题是任何语言都无法回避的问题,可以说I/o问题是整个人机交互的核心问题,因为I/O是机器获取和交换信息的主要渠道。大数据时代,I/O问题很突出,经常成为一个方案的技术瓶颈。
- I/O只是人与机器或者是机器与机器交换数据的手段。
计算机对数据的输入输出
-
助解图
可以看出所谓输入是外部数据向cpu输入,而输出是CPU将数据输出到我们可见的地方,比如文件,屏幕,而计算机通常是通过流来传递数据java I/O
- 根据走向:分为输入流和输出流
- 根据处理数据类型:字节流和字符流
字节流和字符流的解释
- 字节流可以处理所有类型数据,如MP3、图片、文字、视频等。在java中对应的类都以Stream结尾。
- 字符流仅能够处理纯文本数据,如txt等。在java中都以Reader和Writer结尾。
字节,字符,编码的区别?
- 字节是信息单位。字符是记录信息的符号,如“1”,“a”,“#”等等。
- 字符集又叫编码,各国有各自不同的编码,比如“GB2312”,汉子标准。
怎样利用字节输入流和输出流进行文件读写?
-
输入流
public static void fileInputTest(){ try { FileInputStream fileInputStream= new FileInputStream("C://Users//Timmy//Desktop//1234.txt"); byte [] b =new byte[230]; while (fileInputStream.read(b) != -1) { fileInputStream.read(b); String s = new String(b, "GB2312"); System.out.println(s); } fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
输出流
public static void fileoutputTest(){ try { FileOutputStream fileOutputStream = new FileOutputStream("C://Users//Timmy//Desktop//1235.txt"); String a ="你好,你很靓丽"; byte[]b=a.getBytes("GB2312"); fileOutputStream.write(b); fileOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
千万要注意:对于输入流和输出流,使用完之后,一定用各自的close()方法将其关闭;
怎样利用文件的输入流和输出流实现文件的拷贝?
public static void picCopy(){ try { FileInputStream fileInputStream =new FileInputStream("C:\\Users\\Timmy\\Desktop\\streamtest\\1234.JPG"); FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Timmy\\Desktop\\streamtest\\12345.JPG"); byte [] b =new byte[60]; while (fileInputStream.read(b)!=-1){ fileOutputStream.write(b); } fileOutputStream.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
首先说明一下:fo.read(input);返回的是整形,返回的是 从文件中读取数据到数据的字节长度;每次最多读规定数组大小个字节数据,如果没有从文件中读取到数据,则返回-1;如果文件太大,超过定义数组的字节大小,可以采用循环;
拷贝视频也一样
通过带有缓冲的字节流来读取数据?
-
缓冲区
- 计算机访问外部设备或者文件,要比直接访问内存慢得多。如果我们每次调用read()方法或者writer()方法访问外部设备或文件,cpu就要花在很多时间在等外部相应设备,而不是数据处理。为此,我们开辟一个内存缓冲区的内存区域,程序每次调用read()方法或者writer()方法都是读写在这个缓冲区中。这实际上是牺牲空间来换时间的解决方案。这样cpu的使用率就会大大增加,进而提高整个计算机系统的效率。在字符流操作中,所有的字符都是在内存中形成的,在字符流输出前都将保存在内存对的缓冲区内。
-
缓冲流
- 在读写数据时,使用缓冲区的流是缓冲流。这种流一此先将整个缓冲区写满再一次输入或者输出。减少对文件读写次数,提高cpu效率。
缓冲区和缓冲流存在的原因就是为了提高cpu的效率,减少等带时间,把时间都用到处理数据上。
比如说,家里盖房子,有一堆砖头要搬在工地100米外,单字节的读取就好比你一个人每次搬一块砖头,从堆砖头的地方搬到工地,这样可定很费时间,然后好的方法就是多叫几个小伙伴帮你一起搬砖头,这样因为人多了,每次可以搬十块砖头,但效率还是很低,这就好比我们的字节/字符数组读写操作;然而聪明的人类会用小推车,每次先搬砖头搬到小车上,再利用小推车运到工地上去,这样你或者你的小伙伴们再从小推车上取砖头是不是方便多了呀!这样效率就会大大提高,缓冲流就好比我们的小推车;给砖头暂时提供一个可存放的空间;
-
缓冲流分为字节缓冲流和字符缓冲流。
-
缓冲字节流:BufferInputStream,BufferOutputStream
如何利用缓冲机制对64视频拷贝进一步优化?
-
示例代码
public static void videocopy(){ try { FileInputStream fileInputStream =new FileInputStream("C:\\Users\\Timmy\\Desktop\\streamtest\\12.mp4"); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Timmy\\Desktop\\streamtest\\13.mp4"); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); byte [] b =new byte[50]; while (bufferedInputStream.read(b)!=-1){ bufferedOutputStream.write(b); } bufferedOutputStream.close(); fileOutputStream.close(); bufferedInputStream.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
总是现有普通流,再有缓冲流,既然都是流,所以方法一般都一样,只不过内部实现机制不一样;但是,一般缓冲流比普通流处理文件要快得多,比如,都拷贝大约40mb的视频文件,普通流要2054ms,但是缓冲流仅需138ms(两种方案每次读写数组大小一样);
- 优化
- 如果将每次读的字节数扩大,那么访问文件的次数变少,那么时间也会相应变少。这也从侧面证实了在这一过程中,把大量的时间都花费在访问文件上了。
- BufferedInputStream(InputStream in ,int size):可以通过改变缓冲区大小和每次读取字节数组大小来调整。降低磁盘访问次数,延长磁盘寿命。
java中如何利用字节流进行文件读写?
-
代码示例
public static void ReaderInput(){ try { FileInputStream fileInputStream= new FileInputStream("C://Users//Timmy//Desktop//1234.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"GB2312"); char []c =new char[1000]; while (inputStreamReader.read(c) != -1) { String s = new String(c); System.out.println(s); } inputStreamReader.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
错误示例
public static void ReaderPicCopy(){ try { FileInputStream fileInputStream =new FileInputStream("C:\\Users\\Timmy\\Desktop\\streamtest\\1234.JPG"); InputStreamReader inputStreamReader =new InputStreamReader(fileInputStream,"GB2312"); FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Timmy\\Desktop\\streamtest\\12345.JPG"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"GB2312"); char [] b =new char[60]; while (inputStreamReader.read(b)!=-1){ outputStreamWriter.write(b); } outputStreamWriter.close(); fileOutputStream.close(); inputStreamReader.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
字符只能处理文本
如何利用带有缓冲的字符流进行读写数据?
-
字符流进行读写的时候,有些限制,一些不足之处,比如没有读取行,只能每次读取一个数组的数据,所以有设计了带有缓冲的字符流。并且,减少访问硬盘的次数;其实缓冲区一次性从硬盘提取缓冲区大小的数据量,等向外写出完之后,在从硬盘接着调取剩余的数据;而缓冲区的read等方法,只是从缓冲区往外调取数据,没有真正访问硬盘;这其实也是所有缓冲区意义所在;
-
示例代码
public static void ReaderBufferInput(){ try { FileInputStream fileInputStream= new FileInputStream("C://Users//Timmy//Desktop//1234.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"GB2312"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); FileOutputStream fileOutputStream = new FileOutputStream("C://Users//Timmy//Desktop//12345.txt"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"GB2312"); BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); //PrintWriter printWriter =new PrintWriter() char []c =new char[1000]; while (bufferedReader.read(c) != -1) { outputStreamWriter.write(c); String s = new String(c); //System.out.println(s); } bufferedWriter.close(); outputStreamWriter.close(); fileOutputStream.close(); bufferedReader.close(); inputStreamReader.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
每次读一行
public static void ReaderBufferInputmodify(){ try { FileInputStream fileInputStream= new FileInputStream("C://Users//Timmy//Desktop//1234.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"GB2312"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); FileOutputStream fileOutputStream = new FileOutputStream("C://Users//Timmy//Desktop//12345.txt"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"GB2312"); BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); //PrintWriter printWriter =new PrintWriter( String line; while ((line=bufferedReader.readLine() )!= null) { outputStreamWriter.write(line); //String s = new String(c); //System.out.println(s); } bufferedWriter.close(); outputStreamWriter.close(); fileOutputStream.close(); bufferedReader.close(); inputStreamReader.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
结果
3280 10万以上 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
由于readline只是按\n分隔符来读,所以读出来的并没有包含\n字符。所以写入的新文件不会有换行。下面进行改进
public static void ReaderBufferInputmodify(){ try { FileInputStream fileInputStream= new FileInputStream("C://Users//Timmy//Desktop//1234.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"GB2312"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); FileOutputStream fileOutputStream = new FileOutputStream("C://Users//Timmy//Desktop//12345.txt"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"GB2312"); // BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); PrintWriter printWriter = new PrintWriter(outputStreamWriter); //PrintWriter printWriter =new PrintWriter( String line; while ((line=bufferedReader.readLine() )!= null) { printWriter.println(line); //String s = new String(c); //System.out.println(s); } printWriter.close(); outputStreamWriter.close(); fileOutputStream.close(); bufferedReader.close(); inputStreamReader.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
结果
3280 10万以上 aaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaa
-
如上做法是,在读出的不在换行符基础上,定制换行,所以考虑另外一个api–PrintWriter;
-
有一个注意的地方,最后一次读写,如果缓冲区不被写满,是不会写入或者输出的,那么最后一次缓冲区的内容将会丢失,要用flush方法强制写入。或者初始化时设定参数,new PrintWriter(outputStreamWriter,true);保证每次内容强制输出。
-
Bufferwriter等其他输出api没有就没有对应的功能,所以只能在最后关闭前用flush()方法;
public static void ReaderBufferInputmodify(){ try { FileInputStream fileInputStream= new FileInputStream("C://Users//Timmy//Desktop//1234.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"GB2312"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); FileOutputStream fileOutputStream = new FileOutputStream("C://Users//Timmy//Desktop//12345.txt"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"GB2312"); // BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); PrintWriter printWriter = new PrintWriter(outputStreamWriter); //PrintWriter printWriter =new PrintWriter( String line; while ((line=bufferedReader.readLine() )!= null) { printWriter.println(line); //String s = new String(c); //System.out.println(s); } printWriter.flush(); printWriter.close(); outputStreamWriter.close(); fileOutputStream.close(); bufferedReader.close(); inputStreamReader.close(); fileInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
-
FileReader和FileWriter?
- 其操作方法上和上面差不多,此处略去。