从IO到NIO 之 IO讲解

文章有点长,大概需要阅读20分钟

IO

File类

构造函数

  • File(File parent, String child)
  • File(String pathname)
  • File(String parent, String child)

方法

获取属性

在这里插入图片描述

public boolean isDirectory() 判断是否为文件夹

public boolean isFile() 判断是否为文件

public boolean exists() 判断File对象对应的文件或文件夹是否存在

操作方法

在这里插入图片描述

public boolean delete() 如果此路径名表示一个目录,则该目录必须为空才能删除

mkdirs() 创建多级目录,也可以创建单个目录.

获取目录中的文件或文件夹

在这里插入图片描述

常用listFiles

文件过滤器

在这里插入图片描述

继承FilenameFilter接口,实现accept方法.使用listFiles方法时传入FilenameFilter过滤器的实现类.listFiles会将list中的元素交给过滤器,过滤器返回true则保留元素,否则不保留元素.

例:

//获取path路径下所有文件夹
public class FileDemo {
	public static void main(String[] args) {
		//创建File对象
		File file = new File(path);
		//获取指定目录下的文件夹
		File[] files = file.listFiles(new FileFileterByDir());
		//遍历获取到的所有符合条件的文件
		for (File f : files) {
			System.out.println(f);
		}
	}
}
//过滤器类
class FileFileterByDir implements FileFilter{
	public boolean accept(File pathname) {
		return pathname.isDirectory();
	}
}

IO流

IO流的分类

  • 字节流
    • 字节输入流 InputStream 抽象类
      • FileInputStream 操作文件的字节输入流
      • BufferedInputStream高效的字节输入流
    • 字节输出流 OuputStream抽象类
    • FileOutputStream 操作文件的字节输出流
      • BufferedOutputStream 高效的字节输出流
  • 字符流
    • 字符输入流 Reader抽象类
      • InputStreamReader 输入操作的转换流(把字节流封装成字符流)
      • FileReader 用来操作文件的字符输入流(简便的流)
      • BufferedReader 高效的字符输入流
    • 字符输出流 Writer抽象类
      • OutputStreamWriter 输出操作的转换流(把字节流封装成字符流)
    • FileWriter 用来操作文件的字符输出流(简便的流)
      • BufferedWriter 高效的字符输出流

字节流

字节输出流 OuputStream续写、换行、异常处理

public class FileOutputStreamDemo {
	public static void main(String[] args) {
		File file = new File(path);
		//定义FileOutputStream的引用
		FileOutputStream fos = null;
		try {
			//创建FileOutputStream对象,选择续写模式
			fos = new FileOutputStream(file, true);
			//写出数据,加入换行
			fos.write("abcde/r/n".getBytes());
		} catch (IOException e) {
			System.out.println(e.toString() + "----");
		} finally {
			//一定要判断fos是否为null,只有不为null时,才可以关闭资源
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					throw new RuntimeException("");
				}
			}
		}
	}
}

字节输入流 InputStream 缓冲区

public class FileInputStreamDemo {
	public static void main(String[] args) throws IOException {
		File file = new File(path);
		// 创建一个字节输入流对象,明确数据源。
		FileInputStream fis = new FileInputStream(file);		
		//创建一个字节数组,长度可以定义成1024的整数倍。
		byte[] buf = new byte[1024];		
		int len = 0;
		while((len=fis.read(buf))!=-1){
			System.out.println(new String(buf,0,len));
		}
		fis.close();
	}
}

使用缓冲区复制文件

public class CopyFileByBufferTest {
	public static void main(String[] args) throws IOException {
		File srcFile = new File(srcpath);
		File destFile = new File(destpath);
		// 明确字节流和数据源相关联,输出流和目的源关联。
		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();
	}
}

字符流

FileWriter类

字符输出流写数据的时候,必须要运行一个功能,刷新功能 flush(),刷新缓冲区

close方法在关闭流释放资源之前会执行flush()方法

FileReader类

 /*
  *  字符流复制文本文件,必须是文本文件
  *  字符流查询本机默认的编码表,简体中文GBK
  *  FileReader读取数据源
  *  FileWriter写入到数据目的
  */
public class Copy {
    public static void main(String[] args) {
        FileReader fr = null;
        FileWriter fw = null;
        try{
            fr = new FileReader(srcpath);
            fw = new FileWriter(destpath);
            char[] cbuf = new char[1024];
            int len = 0 ;
            while(( len = fr.read(cbuf))!=-1){
                fw.write(cbuf, 0, len);
                fw.flush();
            }

        }catch(IOException ex){
            System.out.println(ex);
            throw new RuntimeException("复制失败");
        }finally{
            try{
                if(fw!=null)
                    fw.close();
            }catch(IOException ex){
                throw new RuntimeException("释放资源失败");
            }finally{
                try{
                    if(fr!=null)
                        fr.close();
                }catch(IOException ex){
                    throw new RuntimeException("释放资源失败");
                }
            }
        }
    }
}

字符流用法和字节流大同小异,字符流是针对字符的,也就是文本文件,注意字符流的输出要调用flush()函数进行刷新

转换流

OutputStreamWriter

public static void OutputStreamWriterDemo() throws Exception {
    //创建与文件关联的字节输出流对象
    FileOutputStream fos = new FileOutputStream(destpath);
    //创建可以把字符转成字节的转换流对象,并指定编码
    OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
    //调用转换流,把文字写出去,其实是写到转换流的缓冲区中
    osw.write("你好");//写入缓冲区。
    osw.close();
}

InputStreamReader

public static void InputStreamReaderDemo() throws IOException{
    //创建读取文件的字节流对象
    InputStream in = new FileInputStream(srcpath);
    //创建转换流对象 
    //InputStreamReader isr = new InputStreamReader(in);会用本地默认码表读取,将会发生错误解码的错误
    InputStreamReader isr = new InputStreamReader(in,"utf-8");
    //使用转换流去读字节流中的字节
    int ch = 0;
    while((ch = isr.read())!=-1){
        System.out.println((char)ch);
    }
    //关闭流
    isr.close();
}

有如下继承关系:

OutputStreamWriter是FileWriter的父类

InputStreamReader是FileReader的父类

当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类

例如:

使用 FileReader fr = new FileReader("a.txt”);

替代 InputStreamReader isr = new InputStreamReader(new FileInputStream(“a.txt”));

缓冲流

字节缓冲流

//字节缓冲输出流BufferedOutputStream
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();
}

//字节缓冲输入流BufferedInputStream
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();
}

高效复制文件

private static void method4(String src, String dest) throws IOException {
    //1,指定数据源
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
    //2,指定目的地
    BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
    //3,读数据
    byte[] buffer = new byte[1024];
    int len = -1;
    while ( (len = in.read(buffer)) != -1) {
        //4,写数据
        out.write(buffer, 0, len);
    }
    //5,关闭流
    in.close();
    out.close();
}

字符缓冲流

//字节缓冲输出流BufferedOutputStream
private static void write() throws IOException {
    //创建基本的字节输出流
    FileWriter fileOut = new FileWriter("abc.txt");
    //使用高效的流,把基本的流进行封装,实现速度的提升
    BufferedWriter out = new BufferedWriter(fileOut);
    //2,写数据
    out.write("hello");
    out.newLine();
    //3,关闭流
    out.close();
}

//字节缓冲输入流BufferedInputStream
private static void read() throws IOException {
    //1,创建缓冲流对象
    FileReader fileIn = new FileReader("abc.txt");
    //把基本的流包装成高效的流
    BufferedReader in = new BufferedReader(fileIn);
    //2,读数据
    String line = null;
    while ( (line = in.readLine()) != null ) {
        //打印
        System.out.print(line);
    }
    //3,关闭
    in.close();
}

例子:文本复制

public class CopyTextFile {
	public static void main(String[] args) throws IOException {
		//1,指定数据源, 是数据源中读数据,采用输入流
		BufferedReader in = new BufferedReader(new FileReader("file.txt"));
		//2,指定目的地,是把数据写入目的地,采用输出流
		BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt"));
		//3,读数据
		String line = null;
		while ( (line = in.readLine()) != null ) {
			//4,写数据
			out.write(line);
			//写入换行符号
			out.newLine();
		}
		//5,关闭流
		out.close();
		in.close();
	}
}

总结

IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?

  • 首先确定选择哪个抽象类
字节 InputStream OutputStream
文本 Reader Writer
  • 明确数据所在的具体设备。
    • 硬盘:文件 File开头。
    • 内存:数组,字符串。
    • 键盘、屏幕:System.in; System.out;
    • 网络:Socket
  • 是否需要额外功能
    • 转换流。InputStreamReader OutputStreamWriter
    • 缓冲区对象。BufferedXXX

方法:

  • 读数据方法:

read() 一次读一个字节或字符的方法

read(byte[] char[]) 一次读一个数组数据的方法

readLine() 一次读一行字符串的方法(BufferedReader类特有方法)

readObject() 从流中读取对象(ObjectInputStream特有方法)

  • 写数据方法:

write(int) 一次写一个字节或字符到文件中

write(byte[] char[]) 一次写一个数组数据到文件中

write(String) 一次写一个字符串内容到文件中

writeObject(Object ) 写对象到流中(ObjectOutputStream类特有方法)

newLine() 写一个换行符号(BufferedWriter类特有方法)

应用

Properties类

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

特点:

1、Hashtable的子类,map集合中的方法都可以用。

2、该集合没有泛型。键值都是字符串。

3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。

4、有和流技术相结合的方法,是唯一一个能与IO流交互的集合。

方法:

public Object setProperty(String key, String value)调用 Hashtable 的方法 put。

public Set stringPropertyNames()返回此属性列表中的键集,

public String getProperty(String key)用指定的键在此属性列表中搜索属性方法:

public Object setProperty(String key, String value)调用 Hashtable 的方法 put。

public Set stringPropertyNames()返回此属性列表中的键集,

public String getProperty(String key)用指定的键在此属性列表中搜索属性

将集合内容存到文件中

public class PropertiesDemo {
	public static void main(String[] args) throws IOException {
		//1,创建Properties集合
		Properties prop = new Properties();
		//2,添加元素到集合
		prop.setProperty("周迅", "张学友");
		prop.setProperty("李小璐", "贾乃亮");
		prop.setProperty("杨幂", "刘恺威");
		
		//3,创建流
		FileWriter out = new FileWriter("prop.properties");
		//4,把集合中的数据存储到流所对应的文件中
		prop.store(out, "save data");
		//5,关闭流
		out.close();
	}
}

读取文件中的数据,保存到集合

public class PropertiesDemo {
	public static void main(String[] args) throws IOException {
		//1,创建集合
		Properties prop = new Properties();
		//2,创建流对象
		FileInputStream in = new FileInputStream("prop.properties");
		//FileReader in = new FileReader("prop.properties");
		//3,把流所对应文件中的数据 读取到集合中
		prop.load(in);
		//4,关闭流
		in.close();
        System.out.print(prop);
	}
}

序列化流于反序列化流

用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流

用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流

特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。

对象序列化流ObjectOutputStream

注意:只能将支持 java.io.Serializable 接口的对象写入流中

public static void writeObj() throws IOException {
    //1,明确存储对象的文件。
    FileOutputStream fos = new FileOutputStream("tempfile\\obj.object");
    //2,给操作文件对象加入写入对象功能。
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    //3,调用了写入对象的方法。
    oos.writeObject(new Person("wangcai",20));
    //关闭资源。
    oos.close();
}

//Serializable标记型接口
public class Person implements Serializable {
	//给类显示声明一个序列版本号。
    //在修改源码后,依然可以反序列化
	private static final long serialVersionUID = 1L;
...

Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

对象反序列化流ObjectInputStream

public static void readObj() throws IOException, ClassNotFoundException {

    //1,定义流对象关联存储了对象文件。
    FileInputStream fis = new FileInputStream("tempfile\\obj.object");

    //2,建立用于读取对象的功能对象。
    ObjectInputStream ois = new ObjectInputStream(fis);

    Person obj = (Person)ois.readObject();

    System.out.println(obj.toString());
}

当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会琲序列化了。

同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。

打印流

字节打印流 PrintStream

字符打印流 PrintWriter(用这个)

除了构造方法,其他方法完全一致

构造方法就是打印流的输出目的端

PrintStream接收File类型,字符串文件名,字节输出流OutputStream

PrintWriter接收File类型,字符串文件名,字节输出流OutputStream,字符输出流Wtiter

public class PrintWriterDemo {
	public static void main(String[] args) throws IOException {
		//创建流
		//PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"));
		PrintWriter out = new PrintWriter("printFile.txt");
		//2,写数据
		for (int i=0; i<5; i++) {
			out.println("helloWorld");
		}
		//3,关闭流
		out.close();
	}
}

public class PrintWriterDemo2 {
	public static void main(String[] args) throws IOException {
		//创建流
		PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"), true);
		//2,写数据
		for (int i=0; i<5; i++) {
			out.println("helloWorld");
		}
		//3,关闭流
		out.close();
	}
}

print println 都是原样输出

write 要经过编码表

自动刷新

满足两个条件:

1.输出的数据目的必须是流对象 OutputStream、Writer

2.必须调用print、printf、format方法其中一个

public static void main(String[] args) throws IOException {
    //创建流
    FileOutputStream fos = new FileOutputStream(path);
    PrintWriter pw = new PrintWriter(fos, true);
    //2,写数据
    for (int i=0; i<5; i++) {
        pw.println("helloWorld");
    }
    //3,关闭流
    //没关闭之前也可以看到数据,因为自刷新
    pw.close();
}

自动刷新的文本复制

public static void main(String[] args) throws IOException {
    BufferedReader bfr = new BufferedReader(new FileReader(srcpath));
   	PrintWriter pw = new PrintWriter(new FileWrite(destpath),true);
    
    String line = null;
    while((line = bfr.readLine()) != null){
        pw.println(line);
    }
    pw.close();
    bfr.close();
}

Commons-IO工具类

FilenameUtils

这个工具类是用来处理文件名(译者注:包含文件路径)的,他可以轻松解决不同操作系统文件名称规范不同的问题;常用方法:

getExtension(String path):获取文件的扩展名;

getName():获取文件名;

isExtension(String fileName,String ext):判断fileName是否是ext后缀名;

FileUtils

提供文件操作(移动文件,读取文件,检查文件是否存在等等)的方法。常用方法:

readFileToString(File file):读取文件内容,并返回一个String;

writeStringToFile(File file,String content):将内容content写入到file中;

copyDirectoryToDirectory(File srcDir,File destDir);文件夹复制

copyFile(File srcFile,File destFile);文件复制

总结

  • 实现文件内容的自动追加
    FileOutputStream(File file, boolean append)
    FileOutputStream(String fileName, boolean append)
    FileWriter(File, boolean append)
    FileWriter(String fileName, boolean append)
  • 实现文件内容的自动刷新
    PrintStream(OutputStream out, boolean autoFlush)
    PrintWriter(OutputStream out, boolean autoFlush)
    PrintWriter(Writer out, boolean autoFlush)

猜你喜欢

转载自blog.csdn.net/sougou_1323/article/details/89739020
今日推荐