【Java 17】IO流 - File类、IO流原理及流的分类、抽象基类、节点流、缓冲流、转换流、标准输入、输出流、打印流、数据流、对象流、随机存取文件流、NIO.2

本文详细介绍了Java中的IO流,包括File类的使用,如创建、删除、重命名文件,以及获取文件信息的方法。深入探讨了IO流的原理、分类,讲解了抽象基类的读写操作,节点流、缓冲流、转换流的使用,以及标准输入、输出流、打印流、数据流、对象流、随机存取文件流的相关概念和实例。同时,提到了NIO.2中的Path、Paths、Files类的使用和字符编码的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IO流

image-20200831013630394

image-20200831013636634

1 File类的使用

1.1 File类的使用

image-20200831130958455

  1. File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)

  2. File类声明在java.io包下

  3. File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成

  4. 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"

  5. IDEA中

    如果使用JUnit中的单元测试方法测试,相对路径为当前Module下

    如果使用main()测试,相对路径为当前Project下

1.2 常用构造器

image-20200831131006585

此时是内存层面的

//构造器一
//相对路径:相对于当前module下
File file1 = new File("hello.txt");
//绝对路径:包含盘符在内的文件或文件目录的路径
File file2 = new File("F:\\workspace_idea1\\JavaSenior\\day08\\hello.txt");

//构造器二
File file3 = new File("F:\\workspace_idea1", "JavaSenior");

//构造器三
File file4 = new File(file3, "hello.txt");

1.3 路径分隔符

image-20200831131259142

1.4 常用方法

image-20200831131538836

image-20200831131545087

image-20200831131553780

  1. File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成
  2. 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"
  • File类的获取功能

    • public String getAbsolutePath():获取绝对路径
    • public String getPath() :获取路径
    • public String getName() :获取名称
    • public String getParent():获取上层文件目录路径。若无,返回null
    • public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
    • public long lastModified() :获取最后一次的修改时间,毫秒值
    • public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
    • public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
    File file1 = new File("hello.txt");
    File file2 = new File("D:\\io\\hi.txt");
    
    file1.getAbsolutePath();//	D:workspace_idea1\JavaSenior\day08\hello.txt
    file1.getPath();//	hello.txt
    file1.getName();//	hello.txt
    file1.getParent();//	null
    file1.length();//	0
    file1.lastModified();//	0
    
    file2.getAbsolutePath();//	D:\\io\\hi.txt
    file2.getPath();//	D:\\io\\hi.txt
    file2.getName();//	hi.txt
    file2.getParent();//	D:\\io
    file2.length();//	0
    file2.lastModified();//	0
    
    /******************************************/
    
    File file = new File("F:\\workspace_idea1\\JavaSenior");
    
    String[] list = file.list();
    for(String s : list){
        System.out.println(s);
    }
    /*
    .idea
    day01
    day02
    JavaSenior.iml
    jdbc.properties
    myproject03
    out
    src
    */
    
    File[] files = file.listFiles();
    for(File f : list){
        System.out.println(f);
    }
    /*
    F:\\workspace_idea1\\JavaSenior\\.idea
    F:\\workspace_idea1\\JavaSenior\\day01
    F:\\workspace_idea1\\JavaSenior\\day02
    F:\\workspace_idea1\\JavaSenior\\JavaSenior.iml
    F:\\workspace_idea1\\JavaSenior\\jdbc.properties
    F:\\workspace_idea1\\JavaSenior\\myproject03
    F:\\workspace_idea1\\JavaSenior\\out
    F:\\workspace_idea1\\JavaSenior\\src
    */
    
  • File类的重命名功能

    • public boolean renameTo(File dest):把文件重命名为指定的文件路径

      要想保证返回true,需要file1在硬盘中是存在的,且file2不能再硬盘中存在

    File file1 = new File("hello.txt");//存在
    File file2 = new File("D:\\io\\hi.txt");//不能存在
    
    boolean renameTo = file1.renameTo(file2);
    //将file1剪切到file2中且重命名
    
  • File类的判断功能

    • public boolean isDirectory():判断是否是文件目录
    • public boolean isFile() :判断是否是文件
    • public boolean exists() :判断是否存在
    • public boolean canRead() :判断是否可读
    • public boolean canWrite() :判断是否可写
    • public boolean isHidden() :判断是否隐藏
  • File类的创建功能

    • public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
    • public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。
    • public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建 注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目 路径下。
    //文件
    File file1 = new File("hi.txt");
    if(!file1.exists()){
        file1.createNewFile();
    }else{
        file1.delete();
    }
    
    //文件目录
    File file1 = new File("d:\\io\\io.txt");//d:\\io存在的
    boolea mkdir = file1.mkdir();//true
    boolea mkdirs = file1.mkdirs();//true
    
    File file1 = new File("d:\\meiyou\\io.txt");//d:\\meiyou不存在的
    boolea mkdir = file1.mkdir();//false
    boolea mkdirs = file1.mkdirs();//true
    
  • File类的删除功能

    • public boolean delete():删除文件或者文件夹 删除注意事项: Java中的删除不走回收站。 要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
    //要想删除成功,io4文件目录下不能有子目录或文件
    File file3 = new File("D:\\io\\io1\\io4");
    file3.delete();//true
    File file4 = new File("D:\\io");
    file4.delete();//false
    

image-20200831140946489

image-20200831141336852

1.5 小练习

image-20200831141344245

File file = new File("D:\\io\\io1\\hello.txt");//存在的
//创建一个与file同目录下的另外一个文件,文件名为:haha.txt
File destFile = new File(file.getParent(), "haha.txt");//此时是内存层面的
boolean newFile = destFile.createNewFile();
if(newFile){
    System.out.println("创建成功")
}
public class FindJPGFileTest {

	@Test
	public void test1(){
		File srcFile = new File("d:\\code");
		
		String[] fileNames = srcFile.list();
		for(String fileName : fileNames){
			if(fileName.endsWith(".jpg")){
				System.out.println(fileName);
			}
		}
	}
	@Test
	public void test2(){
		File srcFile = new File("d:\\code");
		
		File[] listFiles = srcFile.listFiles();
		for(File file : listFiles){
			if(file.getName().endsWith(".jpg")){
				System.out.println(file.getAbsolutePath());
			}
		}
	}
	/*
	 * File类提供了两个文件过滤器方法
	 * public String[] list(FilenameFilter filter)
	 * public File[] listFiles(FileFilter filter)

	 */
	@Test
	public void test3(){
		File srcFile = new File("d:\\code");
		
		File[] subFiles = srcFile.listFiles(new FilenameFilter() {
			
			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith(".jpg");
			}
		});
		
		for(File file : subFiles){
			System.out.println(file.getAbsolutePath());
		}
	}
	
}
//可以用递归
public class ListFilesTest {

	public static void main(String[] args) {
		// 递归:文件目录
		/** 打印出指定目录所有文件名称,包括子文件目录中的文件 */

		// 1.创建目录对象
		File dir = new File("E:\\teach\\01_javaSE\\_尚硅谷Java编程语言\\3_软件");

		// 2.打印目录的子文件
		printSubFile(dir);
	}

	public static void printSubFile(File dir) {
		// 打印目录的子文件
		File[] subfiles = dir.listFiles();

		for (File f : subfiles) {
			if (f.isDirectory()) {// 文件目录
				printSubFile(f);
			} else {// 文件
				System.out.println(f.getAbsolutePath());
			}

		}
	}

	// 方式二:循环实现
	// 列出file目录的下级内容,仅列出一级的话
	// 使用File类的String[] list()比较简单
	public void listSubFiles(File file) {
		if (file.isDirectory()) {
			String[] all = file.list();
			for (String s : all) {
				System.out.println(s);
			}
		} else {
			System.out.println(file + "是文件!");
		}
	}

	// 列出file目录的下级,如果它的下级还是目录,接着列出下级的下级,依次类推
	// 建议使用File类的File[] listFiles()
	public void listAllSubFiles(File file) {
		if (file.isFile()) {
			System.out.println(file);
		} else {
			File[] all = file.listFiles();
			// 如果all[i]是文件,直接打印
			// 如果all[i]是目录,接着再获取它的下一级
			for (File f : all) {
				listAllSubFiles(f);// 递归调用:自己调用自己就叫递归
			}
		}
	}

	// 拓展1:求指定目录所在空间的大小
	// 求任意一个目录的总大小
	public long getDirectorySize(File file) {
		// file是文件,那么直接返回file.length()
		// file是目录,把它的下一级的所有大小加起来就是它的总大小
		long size = 0;
		if (file.isFile()) {
			size += file.length();
		} else {
			File[] all = file.listFiles();// 获取file的下一级
			// 累加all[i]的大小
			for (File f : all) {
				size += getDirectorySize(f);// f的大小;
			}
		}
		return size;
	}

	// 拓展2:删除指定的目录
	public void deleteDirectory(File file) {
		// 如果file是文件,直接delete
		// 如果file是目录,先把它的下一级干掉,然后删除自己
		if (file.isDirectory()) {
			File[] all = file.listFiles();
			// 循环删除的是file的下一级
			for (File f : all) {// f代表file的每一个下级
				deleteDirectory(f);
			}
		}
		// 删除自己
		file.delete();
	}

}

2 IO流原理及流的分类

2.1 IO流原理

image-20200831141354256

image-20200831141400664

2.2 流的分类

image-20200831141409896

image-20200831141432972

image-20200831141414848

image-20200831141421895

2.3 IO流体系

image-20200831141427747

image-20200901000254525

image-20200901175408592

3 抽象基类

image-20200831235655975

image-20200831235702749

image-20200831235709292

image-20200831235718883

image-20200831235729476

image-20200831235738455

image-20200901161222621

3.1 读入

  1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1

  2. 异常的处理:为了保证资源一定可以执行关闭操作,需要使用try-catch-finally处理

  3. 读入的文件一定要存在,否则就会报FileNotFoundException异常

    fr = new FileReader(file);

    image-20200901161211687

3.1.1 代码步骤规范
  1. File类的实例化
  2. FileReader流的实例化
  3. 读入的操作
  4. 资源的关闭
3.1.2 read()

read():返回读入的一个字符。如果达到文件末尾,返回-1

//将day09下的hello.txt文件内容读入程序中,并输出到控制台
@Test
public void testFileReader(){
    
    FileReader fr = null;
    tyr{
        //1.实例化File类的对象,指明要操作的文件
    	File file = new File("hello.txt");
    
    	//2.提供具体的类
    	fr = new FileReader(file);
    
    	//3.数据的读入
    	//read():返回读入的一个字符。如果达到文件末尾,返回-1
    	int data;
    	while((data = fr.read()) != -1){
        	System.out.print((char)data);
    	}
        
        //int data = fr.read();
    	//while(data != -1){
        //    System.out.print((char)data);
        //	data = fr.read();
    	//}
    
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流的关闭
        try{
            if(fr != null)
                fr.close();
        }catch(IOException){
            e.printStackTrace();
        }
    }
    
}
3.1.3 read(char[] cbuf)

read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1

@Test
public void testFileReader1(){
    
    FileReader fr = null;
    tyr{
        //1.实例化File类的对象,指明要操作的文件
        //File类的实例化
    	File file = new File("hello.txt");
    
    	//2.提供具体的类
        //FileReader流的实例化
    	fr = new FileReader(file);
    
    	//3.数据的读入
        //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
    	char[] cbuf = new char[5];
        int len;
        while((len = fr.read(cbuf)) != -1){
        	
            
            //方式一
            //错误的
            //for(int i = 0;i < cbuf.length;i++){
            //   System.out.print(cbuf[i]);
            //}
            //正确的
            for(int i = 0;i < len;i++){
                System.out.print(cbuf[i]);
            }
            
            //方式二
            //char-->String
            //错误的
        	//String str = new String(cbuf);
            //System.out.print(str);
            //正确的
            String str = new String(cbuf, 0 ,len);
            System.out.print(str);
                
            
        }   
   
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流的关闭
        try{
            if(fr != null)
                fr.close();
        }catch(IOException){
            e.printStackTrace();
        }
    }
    
}

3.2 写出

  1. 输出操作,对应的File可以不存在的。并不会报异常

    File对应的硬盘中的文件如果不存在,在输出的过程中,则会自动创建此文件

    File对应的硬盘中的文件如果已存在:

    • 如果流使用的构造器是FileWriter(file) / FileWriter(file, false):对原有文件覆盖
    • 如果流使用的构造器是FileWriter(file, true):不会对原有文件覆盖,而是在原有文件上追加内容
  2. FileWriter fw = new FileWriter(file);

    FileWriter fw = new FileWriter(file, false);//覆盖

    FileWriter fw = new FileWriter(file, true);//追加

image-20200901161243010

3.2.1 步代码骤规范
  1. 提供File类的对象,指明写出到的文件
  2. 提供FileWriter的对象,用于数据的写出
  3. 写出的操作
  4. 流资源的关闭
3.2.2 writer()
@Test
public void testFileWriter(){
    
    FileWriter fw = null;
    
    try{
        //1.提供File类的对象,指明写出到的文件
    	//若不存在则会自动创建
    	//若已存在则会进行覆盖
    	File file = new File("hello1.txt");
    
    	//2.提供FileWriter的对象,用于数据的写出
    	fw = new FileWriter(file);
    
    	//3.写出的操作
    	//writer():
    	fw.write("I have a dream!");
    	fw.write("I have a dream,too!");
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流的关闭
        try{
            if(fw != null)
                fw.close();
        }catch(IOException){
            e.printStackTrace();
        }
    }
    
}

3.3 读入+写出(复制)

@Test
public void testFileReaderFileWriter(){

    FileReader fr = null;
    FileWriter fw = null;
    
    try{
        //1.创建File类的对象,指明读入和写出的文件
    	File srcfile = new File("hello.txt");
    	File destfile = new File("hello2.txt");
    
    	//2.创建输入流和输出流的对象
    	FileReader fr = new FileReader(srcfile);
    	FileWriter fw = new FileWriter(destfile);
    
    	//3.数据的读入和写出操作
    	char[] cbuf = new char[5];
    	int len;
    	while((len = fr.read(cbuf)) != -1){
    	    fw.write(cbuf, 0 ,len);
    	}
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流的关闭
        try{
            if(fw != null)
                fw.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        
        try{
            if(fr != null)
    			fr.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    
}

3.4 图片等读写

image-20200901161117961

@Test
public void testFileReaderFileWriter(){

    FileInputStream fr = null;
    FileOutputStream fw = null;
    
    try{
        //1.创建File类的对象,指明读入和写出的文件
    	File srcfile = new File("爱情与友情.jpg");
    	File destfile = new File("爱情与友情1.jpg");
    
    	//2.创建输入流和输出流的对象
    	fr = new FileInputStream(srcfile);
    	fw = new FileOutputStream(destfile);
    
    	//3.数据的读入和写出操作
    	byte[] cbuf = new byte[5];
    	int len;
    	while((len = fr.read(cbuf)) != -1){
    	    fw.write(cbuf, 0 ,len);
    	}
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流的关闭
        try{
            if(fw != null)
                fw.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        
        try{
            if(fr != null)
    			fr.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    
}

3.5 指定路径下的文件复制

public void copyFile(String srcPath, String destPath){

    FileInputStream fr = null;
    FileOutputStream fw = null;
    
    try{
        //1.创建File类的对象,指明读入和写出的文件
    	File srcfile = new File(srcPath);
    	File destfile = new File(destPath);
    
    	//2.创建输入流和输出流的对象
    	fr = new FileInputStream(srcfile);
    	fw = new FileOutputStream(destfile);
    
    	//3.数据的读入和写出操作
    	byte[] cbuf = new byte[5];
    	int len;
    	while((len = fr.read(cbuf)) != -1){
    	    fw.write(cbuf, 0 ,len);
    	}
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流的关闭
        try{
            if(fr != null)
                fr.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        
        try{
            if(fw != null)
    			fw.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    
}

4 节点流(或文件流)

image-20200901160755705

FileReader fr = null;
try {
	fr = new FileReader(new File("c:\\test.txt"));
	char[] buf = new char[1024];
	int len;
	while ((len = fr.read(buf)) != -1) {
		System.out.print(new String(buf, 0, len));
	}
} catch (IOException e) {
	System.out.println("read-Exception :" + e.getMessage());
} finally {
	if (fr != null) {
		try {
			fr.close();
		} catch (IOException e) {
			System.out.println("close-Exception :" + e.getMessage());
		}
	}
}

image-20200901160852738

FileWriter fw = null;
try {
	fw = new FileWriter(new File("Test.txt"));
	fw.write("atguigu-songhongkang");
} catch (IOException e) {
	e.printStackTrace();
} finally {
	if (fw != null)
		try {
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
}

5 缓冲流

作用:提高流的读取、写入的速度

原因:内部提供了一个缓冲区

  1. 处理流,就是“套接”再已有的流的基础上

image-20200901164806538

image-20200901164812339

image-20200901164819628

5.1 非文本文件的读写

@Test
public void BufferedStreamTest(){

    FileInputStream fis = null;
    FileOutputStream fos = null;
    BufferedInputStream bis = null;
    
    try{
        //1.造文件
    	File srcfile = new File("爱情与友情.jpg");
    	File destfile = new File("爱情与友情1.jpg");
    
    	//2.造流
        //2.1 造节点流
    	fis = new FileInputStream(srcfile);
    	fos = new FileOutputStream(destfile);
        //2.2 造缓存流
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
    
    	//3.复制:读入和写出操作
    	byte[] buffer = new byte[10];
    	int len;
    	while((len = bis.read(buffer)) != -1){
    	    bos.write(buffer, 0 ,len);
    	}
    }catch(IOException e){
        e.printStackTrace();
    }finally{
        //4.流资源的关闭
        //要求:先关闭外层的流,再关闭内层的流
        try{
            if(bos != null)
                bos.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        
        try{
            if(bis != null)
                bis.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        //说明:再关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略
//        try{
//            if(fos != null)
//                fos.close();
//        }catch(IOException e){
//            e.printStackTrace();
//        }
//        
//        try{
//            if(fis != null)
//    			fis.close();
//        }catch(IOException e){
//            e.printStackTrace();
//        }
    }
    
}

5.2 文本文件的读写

BufferedReader br = null;
BufferedWriter bw = null;
try {
	// 创建缓冲流对象:它是处理流,是对节点流的包装
	br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt"));
	bw = new BufferedWriter(new FileWriter("d:\\IOTest\\dest.txt"));
    
    // 复制:读入和写出操作
    //方式一:使用char[]数组
//    char[] buffer = new char[1024];
//    int len;
//    while((len = br.read(buffer)) != -1){
//        bw.write(buffer, 0 ,len);
//    }
    
    //方式二:
	String str;
	while ((str = br.readLine()) != null) { // 一次读取字符文本文件的一行字符
        //方法一:
        //bw.write(str + "\n");
        //方法二:
		bw.write(str); // 一次写入一行字符串
		bw.newLine(); // 写入行分隔符
	}
	//bw.flush(); // 刷新缓冲区
    
    
} catch (IOException e) {
	e.printStackTrace();
} finally {
	// 关闭IO流对象
	try {
		if (bw != null) {
			bw.close(); // 关闭过滤流时,会自动关闭它所包装的底层节点流
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
    
	try {
		if (br != null) {
			br.close();
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
}

image-20200901164827192

5.3 练习

image-20200901164834658

	@Test
    public void Test1(){

        FileOutputStream fos = null;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("爱情与友情.jpg");
            fos = new FileOutputStream("爱情与友情2.jpg");

            byte[] buffer = new byte[20];
            int len;
            while ((len = fis.read(buffer)) != -1){
                //错误
                //for (byte b : buffer) {
                //    b = (byte) (b ^ 5);
                //}
                //正确
                for (int i = 0; i < len; i++) {
                    buffer[i] = (byte) (buffer[i] ^ 5);
                }

                fos.write(buffer, 0 ,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
/**
 * 练习3:获取文本上字符出现的次数,把数据写入文件
 *
 * 思路:
 * 1.遍历文本每一个字符
 * 2.字符出现的次数存在Map中
 *
 * Map<Character,Integer> map = new HashMap<Character,Integer>();
 * map.put('a',18);
 * map.put('你',2);
 *
 * 3.把map中的数据写入文件
 *
 * @author shkstart
 * @create 2019 下午 3:47
 */
public class WordCount {
    /*
    说明:如果使用单元测试,文件相对路径为当前module
          如果使用main()测试,文件相对路径为当前工程
     */
    @Test
    public void testWordCount() {
        FileReader fr = null;
        BufferedWriter bw = null;
        try {
            //1.创建Map集合
            Map<Character, Integer> map = new HashMap<Character, Integer>();

            //2.遍历每一个字符,每一个字符出现的次数放到map中
            fr = new FileReader("dbcp.txt");
            int c = 0;
            while ((c = fr.read()) != -1) {
                //int 还原 char
                char ch = (char) c;
                // 判断char是否在map中第一次出现
                if (map.get(ch) == null) {
                    map.put(ch, 1);
                } else {
                    map.put(ch, map.get(ch) + 1);
                }
            }

            //3.把map中数据存在文件count.txt
            //3.1 创建Writer
            bw = new BufferedWriter(new FileWriter("wordcount.txt"));

            //3.2 遍历map,再写入数据
            Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
            for (Map.Entry<Character, Integer> entry : entrySet) {
                switch (entry.getKey()) {
                    case ' ':
                        bw.write("空格=" + entry.getValue());
                        break;
                    case '\t'://\t表示tab 键字符
                        bw.write("tab键=" + entry.getValue());
                        break;
                    case '\r'://
                        bw.write("回车=" + entry.getValue());
                        break;
                    case '\n'://
                        bw.write("换行=" + entry.getValue());
                        break;
                    default:
                        bw.write(entry.getKey() + "=" + entry.getValue());
                        break;
                }
                bw.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关流
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }

    }
}

6 转换流

6.1 内容

  1. 转换流:属于字符流

    InputStreamReader:将一个字节的输入流转换为字符的输入流

    OutputStreamWriter:将一个字符的输出流转换为字节的输出流

  2. 作用:提供字节流与字符流之间的转换

  3. 解码:字节、字节数组 ----> 字符数组、字符串

    解码:字符数组、字符串 ----> 字节、字节数组

  4. 字符集

image-20200901212616611

image-20200901212630489

image-20200901212638618

image-20200901212644696

6.2 代码实例

image-20200901212653993

6.2.1 InputStreamReader
public class InputStreamReaderTest {

    @Test
    public void test1(){
        InputStreamReader isr = null;
        try {
            FileInputStream fis = new FileInputStream("dbcp.txt");
            //InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
            //参数2指明了字符集,具体使用哪个字符集,取决于文本文件的字符集
            isr = new InputStreamReader(fis,"UTF-8");

            char[] cbuf = new char[20];
            int len;
            while ((len = isr.read(cbuf)) != -1){
                String str = new String(cbuf,0,len);
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (isr != null){
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

}
6.2.2 OutputStreamWriter
@Test
    public void test2() throws IOException {

        File file1 = new File("dbcp.txt");
        File file2 = new File("dbcp_UTF-8.txt");

        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);

        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");

        char[] cbuf = new char[10];
        int len;
        while ((len = isr.read(cbuf)) != -1){
            osw.write(cbuf, 0 ,len);
        }

        isr.close();
        osw.close();
    }

7 标准输入、输出流

7.1 内容

image-20200902003103449

标准的输入、输出流

  1. System.in:标准的输入流,默认从键盘输入

    System.out:标准的输出流,默认从控制台输出

  2. System类的 setIn(InputStream is) / setOut(PrintSteam ps) 方式重新指定输入和输出的流

7.2 例题与代码实例

image-20200902003108669

image-20200902003119761

public class OtherStream {

    public static void main(String[] args) {

        BufferedReader br = null;
        try {
            InputStreamReader isr = new InputStreamReader(System.in);
            br = new BufferedReader(isr);


            while (true){
                System.out.println("请输入字符串:");
                String data = br.readLine();
                if("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
                    System.out.println("程序结束");
                    break;
                }
                String upperCase = data.toUpperCase();
                System.out.println(upperCase);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    
}

7.3 练习

image-20200902003128767

public class MyInput {
    // Read a string from the keyboard
    public static String readString() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // Declare and initialize the string
        String string = "";

        // Get the string from the keyboard
        try {
            string = br.readLine();

        } catch (IOException ex) {
            System.out.println(ex);
        }

        // Return the string obtained from the keyboard
        return string;
    }

    // Read an int value from the keyboard
    public static int readInt() {
        return Integer.parseInt(readString());
    }

    // Read a double value from the keyboard
    public static double readDouble() {
        return Double.parseDouble(readString());
    }

    // Read a byte value from the keyboard
    public static double readByte() {
        return Byte.parseByte(readString());
    }

    // Read a short value from the keyboard
    public static double readShort() {
        return Short.parseShort(readString());
    }

    // Read a long value from the keyboard
    public static double readLong() {
        return Long.parseLong(readString());
    }

    // Read a float value from the keyboard
    public static double readFloat() {
        return Float.parseFloat(readString());
    }
}

8 打印流

image-20200902012713865

  1. 提供了一系列重载的print() 和 println()
	@Test
    public void test2(){
        PrintStream ps = null;
        try {
            FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
            ps = new PrintStream(fos, true);
            if (ps != null) {// 把标准输出流(控制台输出)改成文件
                System.setOut(ps);
            }
            for (int i = 0; i <= 255; i++) { // 输出ASCII字符
                System.out.print((char) i);
                if (i % 50 == 0) { // 每50个数据一行
                    System.out.println(); // 换行
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }

9 数据流

image-20200902014230378

  1. DataInputStream 和 DataOutputSteam
  2. 作用:用于读取或写出基本数据类型的变量或字符串
	@Test
    public void test3(){

        DataOutputStream dos = null;
        try {
            dos = new DataOutputStream(new FileOutputStream("data.txt"));
            dos.writeUTF("吴");
            dos.flush();//刷新操作,一旦执行,就会将内存中的数据写入文件
            dos.writeInt(23);
            dos.flush();
            dos.writeBoolean(true);
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(dos != null){
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。

注意点:读取不同的数据的顺序要与当初写入文件时,保存的数据的顺序要一致

	@Test
    public void test4(){
        DataInputStream dis = null;
        try {
            dis = new DataInputStream(new FileInputStream("data.txt"));

            String name = dis.readUTF();
            int age = dis.readInt();
            boolean isMale = dis.readBoolean();

            System.out.println("name = " + name);
            System.out.println("age = " + age);
            System.out.println("isMale = " + isMale);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(dis != null){
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

10 对象流

10.1 内容

image-20200902100643299

  1. ObjectInputStream 和 OjbectOutputSteam

  2. 作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可 以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

  3. 序列化:将内存中的java对象保存到磁盘中或通过网络传输出去

    使用OjbectOutputSteam实现

    反序列化:将磁盘文件或网络中的对象还原为内存中的一个java对象

    使用OjbectOutputSteam实现

10.2 对象的序列化机制

image-20200902130107705

image-20200902130156687

image-20200902130203367

  • 对象序列化机制:
    • 序列化:允许把内存中的Java对象转换成平台无关的二进制流,从 而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传 输到另一个网络节点。
    • 反序列化:当其它程序获取了这种二进制流,就可以恢复成原 来的Java对象

10.3 使用对象流序列化对象

image-20200902100713637

image-20200902100722331

10.3.1 对象序列化的要求

image-20200902130156687

image-20200902130203367

标识接口:Serializable

image-20200902130350539

要想一个java对象是可序列化的,需要满足的要求:

  1. 需要实现接口:Serializable
  2. 需要当前类提供一个全局常量:serialVersionUID
  3. 除了当前Person类需要实现Seralizable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型是可序列化的)

补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量

public class Person implements Serializable{
    
    //序列版本号
    public static final long serialVersionUID = 423523522L;
    
    private String name;
    private int age;
    private Account account;
    
    //toSring()、get、set、构造器
}

public class Account implements Serializable{
    
    //序列版本号
    public static final long serialVersionUID = 523522L;
    
    private double balance;
    
    //toSring()、get、set、构造器
}
10.3.2 序列化
	@Test
    public void testObjectOutputStream(){

        ObjectOutputStream oos = null;

        try {
            //1.造文件、造流
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));

            //2.写出操作
            oos.writeObject(new String("你好"));
            oos.flush();//刷新操作
            
            oos.writeObject(new Person("吴",20));
            oos.flush();//刷新操作
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭流资源
            if(oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
10.3.3 反序列化
	@Test
    public void testObjectInputStream() {
        ObjectInputStream ois = null;

        try {
            //1.造文件、造流
            ois = new ObjectInputStream(new FileInputStream("object.dat"));

            //2.读取操作
            Object obj = ois.readObject();
            String str = (String)obj;
            Object obj = ois.readObject();
            Person p = (Person)obj;
            
            System.out.println(str);
            System.out.println(p);
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            //3.关闭流资源
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

10.4 面试题

image-20200902100729393

11 随机存取文件流

11.1 内容

image-20200902140038450

image-20200902140046906

image-20200902140053495

11.2 读写操作

image-20200902140108220

image-20200902140113935

image-20200902140126334

11.3 代码实例

11.3.1 普通非文本文件读写
	@Test
    public void test1(){

        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            //1.造文件、造流
            raf1 = new RandomAccessFile(new File("爱情与友情.jpg"), "r");
            raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"), "rw");

            //2.读写操作
            byte[] buffer = new byte[1024];
            int len;
            while ((len = raf1.read(buffer)) != -1){
                raf2.write(buffer,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭流资源
            if(raf1 != null){
                try {
                    raf1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(raf2 != null){
                try {
                    raf2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
11.3.2 普通文本文件写出
  • 如果RandomAccessFile作为输出流时
    • 如果写出到的文件不存在,则执行过程中自动创建
    • 如果如果写出到的文件存在,则会对原有文件内容进行覆盖(默认情况下,从头覆盖,如果写得比较短,只覆盖一部分)
	@Test
    public void test2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

        raf1.write("xyz".getBytes());

        raf1.close();

    }

image-20200902145303161

image-20200902145336527

11.3.3 任意位置读写

image-20200902144837216

11.3.3.1 任意覆盖
	@Test
    public void test2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

        raf1.seek(3);//将指针调到角标为3的位置(第4个字符),覆盖的效果
        raf1.write("xyz".getBytes());

        raf1.close();

    }

image-20200902145344597

image-20200902145406094

11.3.3.2 追加
	@Test
    public void test2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

        raf1.seek(new File("hello.txt").length());
        raf1.write("你好阿".getBytes());

        raf1.close();

    }

image-20200902145406094

image-20200902145529639

11.3.3.3 插入

先把要插入位置后面的字符存起来

	@Test
    public void test3() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

        //将指针调到角标为3的位置
        raf1.seek(3);

        //保存指针3后面的所有数据到StringBuilder builder字符串中
        StringBuilder builder = new StringBuilder((int)new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len));
        }

        //调回指针,写入"xyz"
        raf1.seek(3);
        raf1.write("xyz".getBytes());

        //将StringBuilder builder字符串中的数据写入到文件中
        raf1.write(builder.toString().getBytes());

        raf1.close();
    }

image-20200902140134046

12 NIO.2中Path、Paths、Files类的使用

image-20200902152223093

image-20200902152236890

image-20200902152247518

image-20200902152257070

image-20200902152311544

image-20200902152317635

image-20200902152323464

package com.wmiao.java;

import org.junit.Test;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 1. jdk 7.0 时,引入了 Path、Paths、Files三个类。
 * 2.此三个类声明在:java.nio.file包下。
 * 3.Path可以看做是java.io.File类的升级版本。也可以表示文件或文件目录,与平台无关
 * <p>
 * 4.如何实例化Path:使用Paths.
 * static Path get(String first, String … more) : 用于将多个字符串串连成路径
 * static Path get(URI uri): 返回指定uri对应的Path路径
 *
 * @author shkstart
 * @create 2019 下午 2:44
 */
public class PathTest {

    //如何使用Paths实例化Path
    @Test
    public void test1() {
        Path path1 = Paths.get("d:\\nio\\hello.txt");//new File(String filepath)

        Path path2 = Paths.get("d:\\", "nio\\hello.txt");//new File(String parent,String filename);

        System.out.println(path1);
        System.out.println(path2);

        Path path3 = Paths.get("d:\\", "nio");
        System.out.println(path3);
    }

    //Path中的常用方法
    @Test
    public void test2() {
        Path path1 = Paths.get("d:\\", "nio\\nio1\\nio2\\hello.txt");
        Path path2 = Paths.get("hello.txt");

//		String toString() : 返回调用 Path 对象的字符串表示形式
        System.out.println(path1);

//		boolean startsWith(String path) : 判断是否以 path 路径开始
        System.out.println(path1.startsWith("d:\\nio"));
//		boolean endsWith(String path) : 判断是否以 path 路径结束
        System.out.println(path1.endsWith("hello.txt"));
//		boolean isAbsolute() : 判断是否是绝对路径
        System.out.println(path1.isAbsolute() + "~");
        System.out.println(path2.isAbsolute() + "~");
//		Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径
        System.out.println(path1.getParent());
        System.out.println(path2.getParent());
//		Path getRoot() :返回调用 Path 对象的根路径
        System.out.println(path1.getRoot());
        System.out.println(path2.getRoot());
//		Path getFileName() : 返回与调用 Path 对象关联的文件名
        System.out.println(path1.getFileName() + "~");
        System.out.println(path2.getFileName() + "~");
//		int getNameCount() : 返回Path 根目录后面元素的数量
//		Path getName(int idx) : 返回指定索引位置 idx 的路径名称
        for (int i = 0; i < path1.getNameCount(); i++) {
            System.out.println(path1.getName(i) + "*****");
        }

//		Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象
        System.out.println(path1.toAbsolutePath());
        System.out.println(path2.toAbsolutePath());
//		Path resolve(Path p) :合并两个路径,返回合并后的路径对应的Path对象
        Path path3 = Paths.get("d:\\", "nio");
        Path path4 = Paths.get("nioo\\hi.txt");
        path3 = path3.resolve(path4);
        System.out.println(path3);

//		File toFile(): 将Path转化为File类的对象
        File file = path1.toFile();//Path--->File的转换

        Path newPath = file.toPath();//File--->Path的转换

    }


}
package com.wmiao.java;

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.*;
import java.util.Iterator;

/**
 * Files工具类的使用:操作文件或目录的工具类
 * @author shkstart
 * @create 2019 下午 2:44
 */
public class FilesTest {

	@Test
	public void test1() throws IOException{
		Path path1 = Paths.get("d:\\nio", "hello.txt");
		Path path2 = Paths.get("atguigu.txt");
		
//		Path copy(Path src, Path dest, CopyOption … how) : 文件的复制
		//要想复制成功,要求path1对应的物理上的文件存在。path1对应的文件没有要求。
//		Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING);
		
//		Path createDirectory(Path path, FileAttribute<?> … attr) : 创建一个目录
		//要想执行成功,要求path对应的物理上的文件目录不存在。一旦存在,抛出异常。
		Path path3 = Paths.get("d:\\nio\\nio1");
//		Files.createDirectory(path3);
		
//		Path createFile(Path path, FileAttribute<?> … arr) : 创建一个文件
		//要想执行成功,要求path对应的物理上的文件不存在。一旦存在,抛出异常。
		Path path4 = Paths.get("d:\\nio\\hi.txt");
//		Files.createFile(path4);
		
//		void delete(Path path) : 删除一个文件/目录,如果不存在,执行报错
//		Files.delete(path4);
		
//		void deleteIfExists(Path path) : Path对应的文件/目录如果存在,执行删除.如果不存在,正常执行结束
		Files.deleteIfExists(path3);
		
//		Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置
		//要想执行成功,src对应的物理上的文件需要存在,dest对应的文件没有要求。
//		Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE);
		
//		long size(Path path) : 返回 path 指定文件的大小
		long size = Files.size(path2);
		System.out.println(size);

	}

	@Test
	public void test2() throws IOException{
		Path path1 = Paths.get("d:\\nio", "hello.txt");
		Path path2 = Paths.get("atguigu.txt");
//		boolean exists(Path path, LinkOption … opts) : 判断文件是否存在
		System.out.println(Files.exists(path2, LinkOption.NOFOLLOW_LINKS));

//		boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录
		//不要求此path对应的物理文件存在。
		System.out.println(Files.isDirectory(path1, LinkOption.NOFOLLOW_LINKS));

//		boolean isRegularFile(Path path, LinkOption … opts) : 判断是否是文件

//		boolean isHidden(Path path) : 判断是否是隐藏文件
		//要求此path对应的物理上的文件需要存在。才可判断是否隐藏。否则,抛异常。
//		System.out.println(Files.isHidden(path1));

//		boolean isReadable(Path path) : 判断文件是否可读
		System.out.println(Files.isReadable(path1));
//		boolean isWritable(Path path) : 判断文件是否可写
		System.out.println(Files.isWritable(path1));
//		boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在
		System.out.println(Files.notExists(path1, LinkOption.NOFOLLOW_LINKS));
	}

	/**
	 * StandardOpenOption.READ:表示对应的Channel是可读的。
	 * StandardOpenOption.WRITE:表示对应的Channel是可写的。
	 * StandardOpenOption.CREATE:如果要写出的文件不存在,则创建。如果存在,忽略
	 * StandardOpenOption.CREATE_NEW:如果要写出的文件不存在,则创建。如果存在,抛异常
	 *
	 * @author shkstart 邮箱:shkstart@126.com
	 * @throws IOException
	 */
	@Test
	public void test3() throws IOException{
		Path path1 = Paths.get("d:\\nio", "hello.txt");

//		InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象
		InputStream inputStream = Files.newInputStream(path1, StandardOpenOption.READ);

//		OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象
		OutputStream outputStream = Files.newOutputStream(path1, StandardOpenOption.WRITE,StandardOpenOption.CREATE);


//		SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。
		SeekableByteChannel channel = Files.newByteChannel(path1, StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);

//		DirectoryStream<Path>  newDirectoryStream(Path path) : 打开 path 指定的目录
		Path path2 = Paths.get("e:\\teach");
		DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path2);
		Iterator<Path> iterator = directoryStream.iterator();
		while(iterator.hasNext()){
			System.out.println(iterator.next());
		}


	}
}

13 补充:字符编码

image-20200902002706653

image-20200902002725033

image-20200902002759219

image-20200902002807363

image-20200902002815453

image-20200902002821280

14 IDEA导入jar包

  1. image-20200902153234960

  2. image-20200902153325125

  3. image-20200902153255107

  4. image-20200902153454062

  5. image-20200902153526724

  6. image-20200902153805606

  7. image-20200902153853919

  8. import java.io.File;
    import java.io.IOException;
    
    /**
     * @author wmiao
     * @version 1.0
     * @description: TODO
     * @date 2020/9/2 15:36
     */
    
    public class FileUtilsTest {
    
        public static void main(String[] args) {
            File srcFile = new File("Day09\\爱情与友情.jpg");
            File destFile = new File("Day09\\爱情与友情2.jpg");
            try {
                FileUtils.copyFile(srcFile, destFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值