fos2 这个变量没有进行初始化,所以在使用的时候报了空指针异常,fos2 初始化一下就好,就像你的fos变量一样:fos =
new
FileOutputStream(
"fix.txt"
);
c 的意义在于临时存放当前 while 循环读到的字节内容,以便在循环体内多次引用。如果直接换成 bis.read(),则每调用一次,读到的内容都是下一个字节,逻辑就全乱了。
要么重命名当前类名。要么在类前面加上完整的路径。
1、byteBybyte 模式,是程序从硬盘上读取一个字节字后,再写入一个字节,然后再读取再写入,因为磁盘io的速度是非常慢的,所以耗时较长
2、缓冲实在byteBybyte基础上,方法内部根据一定的算法(也可以能是固定长度,没有看具体实现)在内存中开辟一个空间-缓冲区,读取一个(或者若干个)字节之后,先放入内存缓冲区,然后写入的时候,从缓冲区中写入硬盘。
3、因为内存的io速度非常快,因此可以更为高效的利用硬盘,所以整体上就快了。
你找错目录了,不是bin下的,而是src下的
FileOutputStream的write(int)是直接把字节写到磁盘文件上,相当于直接从这个山头的缸中取了一滴水,然后爬到另一个山头放入那个缸中。
FileOutputStream的write(byte[])是直接把字节先写到字节数组中,然后统一写到磁盘文件上,相当于直接从这个山头的缸中舀一瓢水,然后爬到另一个山头倒入那个缸中。
DataOutputStream的writeXxx()理解跟FileOutputStream的write(byte[])差不多
BufferedOutputStream的write(int)方法相当于把字节一个一个放入一个缓冲区中,再一次性将缓冲区中的内容写到磁盘文件上。相当于将这个山头的水缸中的水一滴一滴放入铁桶中,当这个水缸的水放完了,你再抱着这个铁桶一次性的将水倒入另一个山头的缸中。
BufferedOutputStream的write(byte[])方法是最牛逼的,把字节一部分一部分的拿出,每次拿出都放入字节数组,再将字节数组放入缓冲区中,再一次性将缓冲区中的内容写到磁盘文件上。相当于从这个山头的水缸中一瓢一瓢的舀水放入铁桶中,当这个水缸舀完了,你再抱着这个铁桶一次性的将水倒入另一个山头的缸中。
你说哪个方法走的路少比较轻松? 下面是我的代码,DataOutputStream的没有写。你比较下
package com.imooc.io;
import java.io.*;
public class IOUtil {
public static void copyFileByByte(File sourceFile,File destinationFile) throws IOException{
if( !sourceFile.exists() ) {
throw new IllegalArgumentException(sourceFile+"文件不存在");
}
if( !sourceFile.isFile() ) {
throw new IllegalArgumentException(sourceFile+"不是文件");
}
FileInputStream fis=new FileInputStream(sourceFile);
FileOutputStream fos=new FileOutputStream(destinationFile);
int b;
while( (b=fis.read())!=-1 ) {
fos.write(b);
fos.flush(); //最好加上
}
fis.close();
fos.close();
}
public static void copyFileByByteArray(File sourceFile,File destinationFile) throws IOException{
if( !sourceFile.exists() ) {
throw new IllegalArgumentException(sourceFile+"文件不存在");
}
if( !sourceFile.isFile() ) {
throw new IllegalArgumentException(sourceFile+"不是文件");
}
FileInputStream fis=new FileInputStream(sourceFile);
FileOutputStream fos=new FileOutputStream(destinationFile);
byte[] buf=new byte[16*1024];
int b;
while( (b=fis.read(buf,0,buf.length))!=-1 ) {
fos.write(buf,0,b);
fos.flush(); //最好加上
}
fis.close();
fos.close();
}
public static void copyFileByBufferByByte(File sourceFile,File destinationFile) throws IOException{
if( !sourceFile.exists() ) {
throw new IllegalArgumentException(sourceFile+"文件不存在");
}
if( !sourceFile.isFile() ) {
throw new IllegalArgumentException(sourceFile+"不是文件");
}
BufferedInputStream bis=new BufferedInputStream( new FileInputStream(sourceFile) );
BufferedOutputStream bos=new BufferedOutputStream( new FileOutputStream(destinationFile) );
int b=0;
while( (b=bis.read())!=-1 ) {
bos.write(b);
}
bos.flush();
bis.close();
bos.close();
}
public static void copyFileByBufferByByteArray(File sourceFile,File destinationFile) throws IOException{
if( !sourceFile.exists() ) {
throw new IllegalArgumentException(sourceFile+"文件不存在");
}
if( !sourceFile.isFile() ) {
throw new IllegalArgumentException(sourceFile+"不是文件");
}
BufferedInputStream bis=new BufferedInputStream( new FileInputStream(sourceFile) );
BufferedOutputStream bos=new BufferedOutputStream( new FileOutputStream(destinationFile) );
byte[] buf=new byte[16*1024];
int b=0;
while( (b=bis.read(buf,0,buf.length))!=-1 ) {
bos.write(buf,0,buf.length);
}
bos.flush();
bis.close();
bos.close();
}
}
格式化代码,方便查看和编写
因为你的只导入了BufferReader的包,没有导入其余流对应的包 你可以改为1.导入你目前代码中使用的流包2.直接导入java.io.*所有的IO包
理论上是不通的。
按道理应该是批量比缓冲更快。可以看一下源码,知道缓冲底层调的是批量。如果数据不对,试一下多试几次。有可能是JVM垃圾收集影响了。还有要拷贝不同的文件。读过的文件操作系统有缓存了。拷一个1-2GB的文件试试。
public static void main(String[] args) throws IOException { File srcFile1 = new File("logs/input.iso"); File destFile1 = new File("logs/output.iso"); long beg1 = System.currentTimeMillis(); copyFileByBatch(srcFile1,destFile1); long end1 = System.currentTimeMillis(); System.out.println("批量读取时间毫秒:"+(end1 - beg1));//1261 File srcFile2 = new File("logs/input2.iso"); File destFile2 = new File("logs/output2.iso"); long beg2 = System.currentTimeMillis(); copyFileByBuffer(srcFile2,destFile2); long end2 = System.currentTimeMillis(); System.out.println("批量缓冲读取时间毫秒:"+(end2 - beg2));//1899 }
因为他在内存中创建了byte数组,读写是在内存中进行的,所以快多了
可以不使用静态方法,不使用静态方法,在Test类中就需要先创建一个IOUtil iu = new IOUtil()对象,
通过iu.copyFileByBuffer();方法调用,使用静态方法就可以直接IOUtil.copyFileByBuffer();就可以使用了
1.read这个函数就是读取字节的
2.缓冲区的默认大小好像是8192,以为我在源码中看到private static int defaultBufferSize = 8192;
这句话
3.要是超过缓冲区大小会怎样不知道
这是为啥。。
引用woider所讲的:
使用缓冲字节流复制确实是最快的方式,但对于小文件10M以下的文件体现不出优势,对于百兆文件正确使用,时间可以控制到50ms内。视频中的缓冲字节流使用有错误,复制文件最快的做法是将批量读取到的字节数组使用缓冲写入到文件,在机器性能范围内字节数组越大越快。在循环写入的过程中不需要使用flush,就像cwt8805说的,缓冲输入流在关闭的时候会将所有缓冲区的数据全部写入文件,使用flush刷新缓冲就失去了缓冲的意义。最后关闭IO流和文件流应该在finally中关闭,否则IO异常时执行不到close语句,IO流仍然没有关闭。
因为你的源文件和目标文件名称一样,所以在找目标文件时发现了和目标文件名称一样的源文件,就把源文件删除了重新创建了一个文件,所以你的源文件就没有了,老师视频里面有讲到,当你给出一个路径时,如果没有这个文件他会创建这个文件,如果存在这个文件他会把这个文件删除再创建,如果你不想这个已经存在的文件被删除,只是想要续写他,需要再加一个true,如果我没记错应该是:new File("文件路径",true),具体的你可以再听一遍
我的理解是,视频里面老师展示的是单字节处理,批量处理和单字节带缓冲区处理,其中处理速度:单字节处理<单字节带缓冲区处理<批量处理。但是并没有讲到批量带缓冲区处理,也许你试试这种方法更快。
记事本里采用的是默认编码是ANSI,但是你项目中有很多编码方式,java默认的是utf-16be,你写汉字时使用的是writeUTF()这使用的是utf-8编码,你代码中也有注释的,所以编码方式不统一,自然会出现乱码
啦啦啦啦啦啦啦啦啦啦啦啦
比如从一个缸往另一个缸中倒水,前者直接到,后者是有缓冲区的,相当于一个桶,然后往桶里加水,然后再往另一个缸中到。 字节数组最快(批量),有缓冲区的次之(一杯一杯加到桶里再将桶中的倒入缸中),一个字节一个字节最慢(相当于一杯一杯)。 太详细的有点啰嗦,将就看吧。
从输入流读取下一个字节,可以查看API
你觉得是哪出错了。。。。
这很正常,我们每次开机时间都不一样,有些许差距是正常的,
贴代码上来。。你的问题应该是IO流中的用读写类拷贝文件的操作。
问题原因应该是粗心。。
可能是:要拷贝的源文件路径写成了要拷贝到的路径
如: 源文件: F:/a.txt 拷贝到: F:/b.txt
你写成了: 源文件: F:/b.txt 拷贝到: F:/b.txt
或者是:要拷贝的源文件路径写成了源文件路径
如: 源文件: F:/a.txt 拷贝到: F:/b.txt
写成了: 源文件: F:/a.txt 拷贝到: F:/a.txt
从头仔细查看下代码,或者重写一遍。。即可
copyFile()是上上节课讲过的方法,只是在此调用比较一下,copyFile()批量写入最快
copyFileByBuffer这里是一个字节一个字节读的--->(c=bis.read())!=-1,并非批量,应将它与copyFileByByte的速度相比,是快的。
如果copyFileByBuffer使用字节数组读取--->(b=in.read(buf, 0, buf.length))!=-1,
那么会比同样使用字节数组批量读取的copyFile快。
你可以查看inputstream的read()方法
read()
从输入流中读取数据的下一个字节
c是一个byte
更直观一点的话,你可以通过打印c并且通过对c被写入的次数计数来看
int c; int count=0; while((c = bis.read())!= -1){ System.out.println(c); count++; bos.write(c); bos.flush(); } System.out.println("c被写入了"+count+"次");
视屏右下角