输入输出(IO)流——一个编程小白的Java SE学习日志10【极客BOY-米奇】

前言(转载请说明作者!)4.30~5.7编写

  • 2020.5.5 发布

File类

File类,表示文件或者文件夹,负责文件的本身,而不负责文件的内容。

即它可以获取位置、名字、长度等不涉及内容的操作。

File类的构造方法

方法描述
File(String pathname)传入一个字符串类型的文件路径来创建一个新的File对象
File(String parent,String child)传入一个字符串类型的父路径和一个字符串类型的子路径(包括文件名称)来创建一个File对象
File(File parent,String child)传入指定的File类的父路径和字符串类型的子路径(包括文件名称)创建一个File对象

File类常用方法

方法描述
boolean exists()判断文件是否存在
boolean canWrite()判断文件是否可写
boolean canRead()判断文件是否可读
boolean isFile()判断是否为文件
boolean isDirectory()判断当前文件是否是目录
long lastModified()获取文件最后一次修改时间
long length()获取文件的长度 以字节为单位
boolean delete()删除当前文件
boolean renameTo(File dest)重命名当前File对象表示的文件
String getAbsolutePath()获取文件的绝对路径
String getName()获取文件的名称
---------------------------------------
boolean mkdir()创建当前File对象指定的目录
public String[] list()以字符串数组返回当前文件夹下的所有文件
public File[] listFiles()以文件数组返回当前文件夹下的所有文件
public String[] list(FilenameFilter filter)
public File[] listFiles(FilenameFilter filter)
FilenameFilter是一个接口
boolean accept(File dir,String filename)
来限制由list()方法返回的文件数量
使之只返回符合某一过滤器的文件

File类的一些常用方法实例

  • e.g. 1
import java.io.File;
import java.io.IOException;

public class FileDemo {
	public static void main(String[] args) {
		File file1 = new File("newFile.txt");
		char mark = File.separatorChar;
		File file2 = new File("D:" + mark);
		if(!file1.exists()) {
			try {
				file1.createNewFile();
			} catch(IOException ex) {
				ex.printStackTrace();
			}
		}
		System.out.println(file1.canRead());
		System.out.println(file1.length());
		System.out.println(file1.getAbsolutePath());
		System.out.println(file1.getName());
		System.out.println(file2.isDirectory());
		
		String[] stringList = file2.list();
		System.out.println("指定目录下的文件为:");
		for (String file : stringList) {
			System.out.println(file);
		}
		File[] fileList = file2.listFiles();
		System.out.println("指定目录下的文件为:");
		for (File file : fileList) {
			System.out.println(file);
		}
	}
}
  • e.g. 2 显示过滤后的文件
import java.io.File;
import java.io.FilenameFilter;

public class FileNameFilterDemo {

	public static void main(String[] args) {
		File file = new File("D:");
		File[] files = file.listFiles(new NameFilter());
		if (files != null) {
			for (File tempFile : files) {
				System.out.println(tempFile);
			}
		}
	}
}

class NameFilter implements FilenameFilter {
	@Override
	public boolean accept(File dir, String name) {
		return name.endsWith(".doc") || name.endsWith(".docx");
	}
}

IO流

IO流的分类

按数据流的方向分类

  • 输入流

    如果数据是从外界流入程序的,就是输入流,反之为输出流。

  • 输出流

按是否直接操作源或目标节点

  • 节点流 节点流中,数据源直接关联程序

    节点流
    数据源
    程序
  • 装饰流

装饰流——层层包装(一层或多层)
数据源
程序

按处理数据单位不同

  • 字节流

    字节(Byte):1Byte = 8bit(位),是最基础的存储单位之一。

  • 字符流

    字符:例如:a、b、c、8000、学……

字节流

无论是文本、图片……,计算机文件都是以二进制(字节)形式存在的,Java的IO流中字节的输入输出提供了一系列的流,统称为字节流

字节流是程序中最常用的流,根据数据的传输方向可将其分为字节输入流和字节输出流。
在io包中,提供了两个抽象类InputStream和OutputStream,它们是字节流的顶级父类

  • inputStream的一些方法
方法声明功能描述
int read()输入流读取一个8位的字节,把它转换为0~255之间的整数,并返回这一整数。
int read(byte[] b)
等同:read(byte[] b, 0 , b.length)
输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取字节的数目b叫做读取数据的缓冲区
int read(byte[] b,int off, int len)输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节数目。
void close()关闭此输入流 并释放与该流关联的所有系统资源。
  • OutputStream的一些方法
方法名说明
write(int b)将指定的字节b写入此输出流。
要写入的字节是参数b的八个低位b的24个高位被忽略
write(byte[] b)将b.length个字节从指定的byte数组写入此输出流。
write(byte[] b, int off, int len)将指定byte数组中从偏移量off开始的len个字节写入此输出流。
flush()刷新输出流,即使缓冲区未满强制输出缓冲区中的字节。
close()关闭此输出流并释放与此流有关的所有系统资源。

字节输入流子类

字节输出流子类

由于计算机中的数据基本都保存在硬盘的文件中,因此操作文件中的数据是一种很常见的操作。针对文件的读写,io包中提供了两个类,分别是FileInputStreamFileOutputStream

包:com.s12

FileInputStreamDemo.java

package com.s12;

import java.io.File;
import java.io.FileInputStream;

public class FileInputStreamDemo {
	public static void main(String[] args) throws Exception {
		String dir = System.getProperty("user.dir"), sep = File.separator;
		// 文件字节输入流
		FileInputStream in = new FileInputStream(dir + sep + "src" + sep + "com"
				+ sep + "s12" + File.separator + "word.txt");
		int b = 0;
		while (true) {
			b = in.read();
			// 如果读不出,则为-1
			if (b == -1) {
				break;
			}
			System.out.print(b + " ");
		}
		in.close();
	}
}

word.txt

HelloInputStream!

FileOutputStreamDemo.java

package com.s12;

import java.io.File;
import java.io.FileOutputStream;

public class FileOutputStreamDemo {
	public static void main(String[] args) throws Exception {
		String str = "信息工程学院", sep = File.separator;
		// FOS后面的true的意思是追加
		FileOutputStream fos = new FileOutputStream(
				"src" + sep + "com" + sep + "s12" + sep + "out.txt", true);
		byte[] bytes = str.getBytes();
		for (byte b : bytes) {
			fos.write(b);
		}
		fos.close();
	}
}

缓冲区

文件复制程序的思路
FileInputStream
FileOutputStream
source
程序
destination

FileCopyDemo.java

package com.s12;

import java.io.*;

public class FileCopyDemo {
	public static void main(String[] args) throws Exception {
		String sep = File.separator,
				thisDir = "src" + sep + "com" + sep + "s12" + sep;
		// 创建一个字节输入流,读取当前目录下out.txt文件
		InputStream in = new FileInputStream(thisDir + "out.txt");
		// 创建一个文件字节输出流,将读取的数据写入到目录中
		OutputStream out = new FileOutputStream(thisDir + "outout.txt");
		try {
			// 记住每个读取的字节
			int b;
			// 获取复制前的系统时间
			long beginTime = System.currentTimeMillis();
			for (; (b = in.read()) != -1; out.write(b))
				;
			// 获取结束时间
			long endTime = System.currentTimeMillis();
			System.out.println("复制文件所用时间:" + (endTime - beginTime) + "ms。");
		} finally {
			in.close();
			out.close();
		}
	}
}

一个一个字节的读写,效率非常低。像从北京运一万个包裹到上海,如果每次运送一个,就必须运输一万次,这样的效率显然非常低。

为了减少运输次数,可以先把一批包裹装在车厢中,这时的车厢就相当于一个临时缓冲区。当通过流的方式拷贝文件时,为了提高效率也可以定义一个字节数组作为缓冲区。在拷贝文件时,可以一次性读取多个字节的数据,并保存在字节数组中,然后将字节数组中的数据一次性写入文件。

  • 方案1
package com.s12;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class NewFileCopyDemo {
	public static void main(String[] args) throws Exception {
		String sep = File.separator,
				thisDir = "src" + sep + "com" + sep + "s12" + sep;
		// 这里使用了Java7后的语法:try-with-resources(try括号里面声明的资源在try后都会关闭)
		try (InputStream in = new FileInputStream(thisDir + "out.txt");
				OutputStream out = new FileOutputStream(
						thisDir + "outout.txt")) {
			byte[] buff = new byte[1024];
			int len;
			long beginTime = System.currentTimeMillis();
			for (; (len = in.read(buff)) != -1; out.write(buff, 0, len))
				;
			long endTime = System.currentTimeMillis();
			System.out.println("复制文件所用时间:" + (endTime - beginTime) + "ms。");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
  • 方案2
package com.s12;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class BufferedCopyDemo {
	public static void main(String[] args) {
		String sep = File.separator,
				thisDir = "src" + sep + "com" + sep + "s12" + sep;
		try (BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(thisDir + "out.txt"));
				BufferedOutputStream bos = new BufferedOutputStream(
						new FileOutputStream(thisDir + "outBuffered.txt"))) {
			int b;
			long beginTime = System.currentTimeMillis();
			// bis里面的read无参方法读取的是缓冲区内容
			for (; (b = bis.read()) != -1; bos.write(b))
				;
			long endTime = System.currentTimeMillis();
			System.out.println("复制文件所用时间:" + (endTime - beginTime) + "ms。");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

这次课带着你认识了缓冲区,用两种方式实现了缓冲区

使用字节缓冲流,读写大文件尤其离不开它。

字符流

InputStream类和OutputStream类在读写文件时操作的都是字节 如果希望在程序中操作字符,使用这两个类就不太方便。

io包提供了字符流。同字节流一样,字符流也有两个抽象的顶级父类,分别是ReaderWriter

Reader

Writer

如需对文本文件的内容 进行读取,想从文件中直接读取字符可以使用字符输入流FileReader,通过此流可以从关联的文件中读取一个或一组字符。

程序演示

package com.s12;

import java.io.File;
import java.io.FileReader;

public class FileReaderDemo {

	public static void main(String[] args) {
		String sep = File.separator,
				thisDir = "src" + sep + "com" + sep + "s12" + sep;
		// FileReader用来读取文件中的字符
		try (FileReader reader = new FileReader(thisDir + "word.txt")) {
			// 变量用于记录读取的字符
			int ch;
			// 不是字符流末尾就转为字符打印
			for (; (ch = reader.read()) != -1; System.out.println((char) ch))
				;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
package com.s12;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {

	public static void main(String[] args) {
		String sep = File.separator,
				thisDir = "src" + sep + "com" + sep + "s12" + sep;
		// FileWriter用于向文件写入数据
		try (FileWriter writer = new FileWriter(thisDir + "writer.txt")) {
			String str = "信工";
			writer.write(str);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

转换流

有时字节流和字符流之间需要进行转换

这时就要用到InputStreamReaderOutputStreamWriter

转换流

package com.s12;

import java.io.*;

public class TransferStreamDemo {

	public static void main(String[] args) throws Exception {
		String sep = File.separator,
				thisDir = "src" + sep + "com" + sep + "s12" + sep;
		FileInputStream in = new FileInputStream(thisDir + "word.txt");
		Reader isr = new InputStreamReader(in);
		BufferedReader br = new BufferedReader(isr);

		FileOutputStream out = new FileOutputStream(thisDir + "dest.txt");
		Writer osw = new OutputStreamWriter(out);
		BufferedWriter bw = new BufferedWriter(osw);
		String line;
		while ((line = br.readLine()) != null) {
			bw.write(line + '\n');
		}
		br.close();
		bw.close();
	}

}

虽然Java中的流很多,但是使用起来并不复杂,要么直接关联源或目标要么一层层的包装流

装饰设计模式

e.g.

  1. FilelnputStream fis= new FileInputStream(new File( “in.txt” );

    文件输入流对象关联了文件

  2. DatalnputStream dis= new DatalnputStream(fis);

    数据流包装文件输入流

  3. InputStreamReader isr = new InputStreamReader(dis);

    转换流转为Reader类型的对象,包装FileInputStream对象

  4. BufferedReader br= new Buffered Reader(isr);
    缓冲流

通过层层装饰,流的功能不断增强。**

Eclipse IDE的主体部分就是Eclipse,我们可以通过安装插件的方式使其功能不断增强。

装饰设计模式就是将程序的主体部分和装饰部分分离,即将变化较小的部分和容易变化的部分分开。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客BOY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值