Java SE 基础复习-IO与序列化(2)-文件操作
本文从File,NetWork,Memory三个角度讲述IO操作
一、文件
1、file.lenght()与inputsstream.avaiable()的区别
a)file.lenght 返回的是long型,available()返回的是int型,后者最大只有2G
b)lenght返回的是文件的大小,avaiable()返回的是在输入流中直接阻塞时的大小。当在本地读取较小文件时,avaiable()也可以简单的理解成文件大小,但是在网络通信的时候,就不能了,我们知道read方法是阻塞的,此时这个inputstream.available()方法返回的值是该inputstream在不被阻塞的情况下一次可以读取到的数据长度。
c)类 InputStream
的 available
方法总是返回 0
。此方法应该由子类重写。
d)FilterInputStream重写了available() 其子类如DataInputStream,BufferInputStream都可以使用该方法。
e).FileInputStream的available() 方法返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
2、三个read方法的区别
a) read()
从这个流中一个字节一个字节的读取,返回的是这个字节的int值
b) read(byte[] b)
这个方法是先规定一个数组长度,将这个流中的字节缓冲到数组b中,返回的这个数组中的字节个数,这个缓冲区没有满的话,则返回真实的字节个数,到未尾时都返回-1.
c) read(byte[] b, int off, int len)
多次read().
3、三个write方法的区别
a) write(int b)
向输出流里写入一个值为 b 的字节。需要注意的是,实际写入的是 int 类型 b 的低8位,其余的 24 位被忽略
b) write(byte[] b)
向输入流里写入一个字节数组b。效果和 write(b, 0, b.length) 相同。调用这个方法时,需要捕获和处理 IOException。OutputStream 和 FileOutputStream 的实现都是调用了下面的方法
c) write(byte[] b, int off, int len)
把位置为 off、长度为len 的字节数组b中的数据写入到输出流中。OutputStream 的实现是反复调用write(int b), 子类应该提供更有效率的实现。
4、文件复制
文件复制常使用FileInputStream和BufferedInputStream或DataInputStream
public class Main { static int SIZE=128*64; public static void main(String[] args) throws Exception{ File iFile=new File("E:/td.rm"); File oFile=new File("E:/td2.rm"); long begin=System.currentTimeMillis(); copyFile(iFile, oFile); long end=System.currentTimeMillis(); System.out.println("FileInputStream耗时"+(end-begin)+"毫秒"); long begin2=System.currentTimeMillis(); copyFileBuffer(iFile, oFile); long end2=System.currentTimeMillis(); System.out.println("BufferedInputStream耗时"+(end2-begin2)+"毫秒"); long begin3=System.currentTimeMillis(); copyFileData(iFile, oFile); long end3=System.currentTimeMillis(); System.out.println("DataInputStream耗时"+(end3-begin3)+"毫秒"); } private static void copyFileBuffer(File src,File des) { InputStream fis=null; OutputStream fos=null; try { byte [] b=new byte[SIZE]; fis=new BufferedInputStream(new FileInputStream(src)); fos=new BufferedOutputStream(new FileOutputStream(des)); int i=0; while((i=fis.read(b)) != -1) { fos.write(b); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { fis.close(); fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private static void copyFileData(File src,File des) { InputStream fis=null; OutputStream fos=null; try { byte [] b=new byte[SIZE]; fis=new DataInputStream((new FileInputStream(src))); fos=new DataOutputStream((new FileOutputStream(des))); int i=0; while((i=fis.read(b)) != -1) { fos.write(b); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { fis.close(); fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private static void copyFile(File src,File des) { InputStream fis=null; OutputStream fos=null; try { byte [] b=new byte[SIZE]; fis=new FileInputStream(src); fos=new FileOutputStream(des); int i=0; while((i=fis.read(b)) != -1) { fos.write(b); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { fis.close(); fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
输出
FileInputStream耗时3203毫秒
BufferedInputStream耗时2531毫秒
DataInputStream耗时2657毫秒
测试了一些可能对速度产生影响的因素,包括缓冲数组的大小,多重包装等等,发现速度是随机的,不过总体来说,BufferednputStream里面的默认缓冲区大小是8192.
BufferedInputStream>=DataInputStream>=FileInputStream
注:上面的BufferedOutPutStream没有使用flush(),触发具体写操作
OutputStream 中这个方法的实现什么也没做。具体子类应该重写这个方法。FileOutputStream 没有使用缓存,因此没有重写这个方法
上面没有使用flush()最终也写进去了,是因为在流关闭的时候会自动触发写操作。
5、获取字节数组
在commons-io包中org.apache.commons.io.IOUtils类的toByteArray(InputStream input)已经有实现了,我们可以参考下思路,完成我们的方法,我们可以用类似下面的代码实现inputStream转化为byte[]数组
public static byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } return output.toByteArray(); }
下面是IOUtils中摘录出与toByteArray相关的方法
org.apache.commons.io.IOUtils.toByteArray 方法如下: public static byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); copy(input, output); return output.toByteArray(); } public static int copy(InputStream input, OutputStream output) throws IOException { long count = copyLarge(input, output); if (count > 2147483647L) { return -1; } return (int)count; } public static long copyLarge(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[4096]; long count = 0L; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步