IO流-File,字节流,缓冲流
1.1 IO概述
回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了。那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据读出来继续使用呢?其实要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等 ROM)上。
当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作。
因此我们把这种输入和输出动作称为IO操作。
1.2 IO流流向分类
按照流向分:输入流与输出流,每个IO流对象均要绑定一个IO资源
分类关系如下:
字节输入流 InputStream的抽象类
FileInputStream 操作文件的字节输入流
字节输出流 OutputStream的抽象类
FileOutputStream 操作文件的字节输出流
按照传输方式:分为字节流和字符流
字符流 按照字符的方式读写
字节流 按照字节的方式读写
1.3 一切均为字节
在数据传输过程中,一切数据(文本、图像、声音等)最终存储的均为一个个字节,即二进制数字。所以数据传输过程中使用二进制数据可以完成任意数据的传递。
第1章 File
在我们操作系统中,数据都保存在文件中,而文件存放相应的文件夹中。那么Java中是如何描述这些的呢?
1.1 File类的出现
打开API,搜索File类。阅读其描述:File文件和目录路径名的抽象表示形式。即,Java中把文件或者目录(文件夹)都封装成File对象。也就是说如果我们要去操作硬盘上的文件,或者文件夹只要找到File这个类即可。那么我们就要研究研究File这个类中都有那些功能可以操作文件或者文件夹呢?
1.2 File类的构造方法
通过构造方法创建File对象,我们进行代码演示:
public static void main(String[] args) { //方法1: String filePath = "G:\\FileTest\\file1.txt"; File file = new File(filePath); System.out.println(file); // 方法2:将parent封装成file对象。 File dir = new File("G:\\FileTest"); File file2 = new File(dir, "hello.java"); //方法3: File file3 = new File("G:\\FileTest", "hello.java"); }
1.3 File类的方法
创建完了File对象之后,那么File类中都有如下常用方法
public static void main(String[] args) throws IOException { String dirPath = "g:\\TestFiles"; //String dirPath = "g:\\TestFile";//注意java创建文件夹和文件名不要包含file,可能存在bug,创建不成功 String filePath = "G:\\TestFiles\\file1.txt"; File dir = new File("g:\\TestFiles"); boolean b1=dir.mkdir();//创建一个空的新文件夹(前提是该文件不存在) File file = new File(filePath); boolean b2=file.createNewFile();//创建一个空的新文件(前提是该文件不存在)注意,要保证该路径下所有的文件夹都已经存在或者在此之前已经创建 // 创建文件,如果文件不存在,创建 true 如果文件存在,则不创建 false。 如果路径错误,IOException。 String absPath=file.getAbsolutePath();//获取文件全路径 String path=file.getPath();//获取我们构造文件的时候的路径(也就是File构造方法里面我们传递的字符串) String name=file.getName();//获取文件名 String parent=file.getParent();//获取父文件夹文件名 boolean isfile=file.isFile();//判断是不是文件(如果文件不存在返回false) boolean isdir=file.isDirectory();//判断是不是文件夹(如果文件夹不存在返回false) boolean canread=file.canRead();//判断是否可读 boolean canwrite=file.canWrite();//判断是否可写 long lenth=file.length();//返回文件的长度 boolean b3=file.exists();//判断文件是否存在 boolean b4 = file.delete();//删除文件操作--删除成功返回true,文件不存在返回false-----注意:不去回收站。慎用------ //删除目录时,如果目录中有内容,无法直接删除返回false。只有将目录中的内容都删除后,保证该目录为空。这时这个目录才可以删除。 boolean b5 = dir.delete(); System.out.println("b1="+b1); System.out.println(absPath); System.out.println(path); System.out.println(name); System.out.println(parent); System.out.println(isfile); System.out.println(isdir); System.out.println(canread); System.out.println(canwrite); System.out.println(lenth); System.out.println(b3); System.out.println(b4); System.out.println(b5);
// 1.1 listFiles()和list()方法介绍
File dir0=new File("g://files"); File dir1=new File("g://files//dir1"); File dir2=new File("g://files//dir2"); File f1=new File("g://files//dir2//test1.txt"); File f2=new File("g://files//dir2//test2.txt"); File f3=new File("g://files//dir1//test3.txt"); if(!dir1.exists()) { dir1.mkdirs(); } if(!dir2.exists()) { dir2.mkdirs(); } if(!f1.exists()) { f1.createNewFile(); } if(!f2.exists()) { f2.createNewFile(); } if(!f3.exists()) { f3.createNewFile(); } String arg1[]=dir0.list();//获取的是目录下的当前的文件以及文件夹的名称。 for(String s: arg1) { System.out.println(s); } File f[]=dir0.listFiles();//获取目录下当前文件以及文件对象,只要拿到了文件对象,那么就可以获取其中想要的信息 for(File ff:f) { System.err.println(ff); }
}
第2章 字节流
既然一切数据都是字节,那么字节流如何操作呢,那么接下来我们进行字节流的学习.
2.1 字节输出流OutputStream
OutputStream此抽象类,是表示输出字节流的所有类的超类。操作的数据都是字节,定义了输出字节流的基本共性功能方法。
输出流中定义都是写write方法;
2.1.1 FileOutputStream类
OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。
FileOutputStream类,即文件输出流,是用于将数据写入 File的输出流。
构造方法:
代码演示:
public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //需求:将数据写入到文件中。 //创建存储数据的文件。 File f1=new File("g://files//dir2//test1.txt"); File f2=new File("g://files//dir2//test2.txt"); File f3=new File("g://files//dir2//test3.txt"); //创建一个用于操作文件的字节输出流对象。一创建就必须明确数据存储目的地。 //输出流目的是文件,会自动创建。如果文件存在,则覆盖。 FileOutputStream fs1=new FileOutputStream(f1); FileOutputStream fs2=new FileOutputStream(f2,true);//第二个参数true标识不是覆盖,而是续写 FileOutputStream fs3=new FileOutputStream(f3); byte b[]="123我很开心".getBytes(); //调用父类的write方法 fs1.write(b);//将b全部写出 fs2.write(b,2,4);//将b里面索引在2-4的内容写出(3我很) fs3.write(10);//这个方法有待研究 //刷新此输出流并强制写出所有缓冲的输出字节 fs1.flush(); //关闭流资源 fs1.close(); fs2.flush(); fs2.close(); fs3.flush(); fs3.close(); }
2.2.1 FileInputStream类
InputStream有很多子类,其中子类FileInputStream可用来读取文件内容。
FileInputStream 从文件系统中的某个文件中获得输入字节。
构造方法:
2.2.2 FileInputStream类读取数据read方法(只读纯英文,有空介绍一下读中文问题)
在读取文件中的数据时,调用read方法,实现从文件中读取数据
代码演示:
public static void main(String[] args) throws Exception { File f1=new File("g://files//dir2//test1.txt"); FileInputStream fis1=new FileInputStream(f1); //读取数据。使用 read();一次读一个字节。 int n; while((n=fis1.read())!=-1) { System.out.println((char)n); } fis1.close(); }
2.2.3 读取数据read(byte[])方法
在读取文件中的数据时,调用read方法,每次只能读取一个,太麻烦了,于是我们可以定义数组作为临时的存储容器,这时可以调用重载的read方法,一次可以读取多个字符。
public static void main(String[] args) throws Exception { File f1=new File("g://files//dir2//test1.txt"); FileInputStream fis1=new FileInputStream(f1); /* * 演示第二个读取方法, read(byte[]); */ int n=0; byte b[]=new byte[1024];//长度可以定义成1024的整数倍。 while((n=fis1.read(b))!=-1) { System.out.println(new String(b,0,n)); } fis1.close(); }
2.3.1 复制文件
原理;读取一个已有的数据,并将这些读到的数据写入到另一个文件中。
public class CopyFileTest { public static void main(String[] args) throws IOException { //1,明确源和目的。 File srcFile = new File("c:\\YesDir\test.JPG"); File destFile = new File("copyTest.JPG"); //2,明确字节流 输入流和源相关联,输出流和目的关联。 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //3, 使用输入流的读取方法读取字节,并将字节写入到目的中。 int ch = 0; while((ch=fis.read())!=-1){ fos.write(ch); } //4,关闭资源。 fos.close(); fis.close(); } }
上述代码输入流和输出流之间是通过ch这个变量进行数据交换的。
上述复制文件有个问题,每次都从源文件读取一个,然后在写到指定文件,接着再读取一个字符,然后再写一个,一直这样下去。效率极低。
2.3.2临时数组方式复制文件
上述代码复制文件效率太低了,并且频繁的从文件读数据,和写数据,能不能一次多把文件中多个数据都读进内容中,然后在一次写出去,这样的速度一定会比前面代码速度快。
public class CopyFileByBufferTest { public static void main(String[] args) throws IOException { File srcFile = new File("c:\\YesDir\test.JPG"); File destFile = new File("copyTest.JPG"); // 明确字节流 输入流和源相关联,输出流和目的关联。 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //定义一个缓冲区。 byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { fos.write(buf, 0, len);// 将数组中的指定长度的数据写入到输出流中。 } // 关闭资源。 fos.close(); fis.close(); } }
第3章 缓冲流
在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么,我想提高速度,怎么办?
Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度
缓冲流,根据流的分类分为字节缓冲流与字符缓冲流。
3.1 字节缓冲流
字节缓冲流根据流的方向,共有2个
l 写入数据到流中,字节缓冲输出流 BufferedOutputStream
l 读取流中的数据,字节缓冲输入流 BufferedInputStream
它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度
3.1.1字节缓冲输出流BufferedOutputStream
通过字节缓冲流,进行文件的读写操作 写数据到文件的操作
l 构造方法
public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
public class BufferedOutputStreamDemo01 { public static void main(String[] args) throws IOException { //写数据到文件的方法 write(); } /* * 写数据到文件的方法 * 1,创建流 * 2,写数据 * 3,关闭流 */ private static void write() throws IOException { //创建基本的字节输出流 FileOutputStream fileOut = new FileOutputStream("abc.txt"); //使用高效的流,把基本的流进行封装,实现速度的提升 BufferedOutputStream out = new BufferedOutputStream(fileOut); //2,写数据 out.write("hello".getBytes()); //3,关闭流 out.close(); } }
3.1.2 字节缓冲输入流 BufferedInputStream
刚刚我们学习了输出流实现了向文件中写数据的操作,那么,现在我们完成读取文件中数据的操作
l 构造方法
public BufferedInputStream(InputStream in)
/* * 从文件中读取数据 * 1,创建缓冲流对象 * 2,读数据,打印 * 3,关闭 */ private static void read() throws IOException { //1,创建缓冲流对象 FileInputStream fileIn = new FileInputStream("abc.txt"); //把基本的流包装成高效的流 BufferedInputStream in = new BufferedInputStream(fileIn); //2,读数据 int ch = -1; while ( (ch = in.read()) != -1 ) { //打印 System.out.print((char)ch); } //3,关闭 in.close(); }
3.3.3 复制单级文件夹
/* * 数据源:e:\\demo * 目的地:e:\\test * * 分析: * A:封装目录 * B:获取该目录下的所有文本的File数组 * C:遍历该File数组,得到每一个File对象 * D:把该File进行复制 */ public class CopyFolderDemo { public static void main(String[] args) throws IOException { // 封装目录 File srcFolder = new File("e:\\demo"); // 封装目的地 File destFolder = new File("e:\\test"); // 如果目的地文件夹不存在,就创建 if (!destFolder.exists()) { destFolder.mkdir(); } // 获取该目录下的所有文本的File数组 File[] fileArray = srcFolder.listFiles(); // 遍历该File数组,得到每一个File对象 for (File file : fileArray) { // System.out.println(file); // 数据源:e:\\demo\\e.mp3 // 目的地:e:\\test\\e.mp3 String name = file.getName(); // e.mp3 File newFile = new File(destFolder, name); // e:\\test\\e.mp3 copyFile(file, newFile); } } private static void copyFile(File file, File newFile) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream( file)); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(newFile)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } }
