IO

一、概述

IO根据要操作对象的类型不同(操作的媒介不同),可以分为多种。Writer/Reader,InputStream/OutputStream为抽象类,定义了IO所通用的方法,包括write(),flush(),close()等。Writer/Reader对应为字符流,可以用来操作中文字符,InputStream/OutputStream为字节流,可以传输图片等。

IO类结构图:

图片来源于网络,侵删。

二、IO

·File媒介

File媒介IO包括FileWriter/FileReader,FileOutputStream/FileInputStream,是针对文件进行读写。

File类对象代表一个文件实例,File类实现Synchorizable接口和Comparable接口,提供方法来对文件进行操作。

在File源码中有一个abstarct pathname,有些费解,个人的理解是其实就是在new File(String pathname)时传递的参数,这样理解的原因是:构建一个file后,调用file.isAbsolute(),判断给出的abstract pathname是否为绝对路径,由这个方法的说明可以知道:传递的pathname参数就是abstract pathname。

-File类操作

public class FileTest {
	public static void main(String[] args) {
		// 对象file代表test.txt文件,""内为pathname
		// File file = new File("H:\\workspace3\\io\\test.txt");
		// 不把分割符写死,便于在win/unix上移植
		File file = new File(
				"H:" + File.separator + "workspace3" + File.separator + "io" + File.separator + "test.txt");
		System.out.println("H:" + File.separator + "workspace3" + File.separator + "io" + File.separator + "test.txt");
		try {
			// 创建test.txt
			file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 文件是否存在
		System.out.println(file.exists());
		// 是否可读
		System.out.println(file.canRead());
		// 文件所在目录
		System.out.println(file.getParent());
		// 文件绝对路径,absolute name
		System.out.println(file.getAbsolutePath());
		// 文件所在目录,通俗理解,返回File()构造方法中的路径
		System.out.println(file.getPath());
		// 判断abstract pathname是否为绝对路径
		System.out.println(file.isAbsolute());
		// 列出同级文件,如果abstract pathname不是目录,返回null
		file.list();
		// 获取filesystem roots:C:\ D:\ E:\
		file.listRoots();
		// 创建目录
		file.mkdir();
		// 创建目录,包括不存在的父目录
		file.mkdirs();
		// 删除文件
		// file.delete();

		System.out.println(File.separator);
		System.out.println(File.pathSeparator);
		System.out.println(File.separatorChar);
	}
}

-FileWriter/FileReader

public class FileRW {
	public static void TestFileWriter(File file) throws IOException {
		//如果文件不存在,创建之
		if (!file.exists()) {
			file.createNewFile();
		}else {
			FileWriter fw = new FileWriter(file,true);
			System.out.println(fw.getEncoding());
			fw.write("张柏芝\n"+"陈冠希\n"+"谢霆锋\n");
			//
			fw.close();
		}
	}
	
	public static void TestFileReader(File file) throws IOException {
		if (!file.exists()) {
			file.createNewFile();
		}
		FileReader fr = new FileReader(file);
		//读取单个字符,如果读完返回-1
		//fr.read();
		char[] content = new char[100];
		fr.read(content);
		System.out.println(new String(content));
		fr.close();
	}
	
	public static void main(String[] args) {
		File file = new File("H:\\workspace3\\io\\test2.txt");
		//写入
		try {
			FileRW.TestFileWriter(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//读取
		try {
			FileRW.TestFileReader(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
}

-FileOutputStream/FileInputStream

public class FileIO {
	
	//FileInputStream,读出
	public static void testFIS(File file) throws IOException {
		FileInputStream fis = new FileInputStream(file);
		// 字符数组,存放数据
		byte[] content = new byte[1024];
		// 如果文件存在,读取到字符数组中
		if (file.exists()) {
			fis.read(content);
		}
		System.out.println(new String(content));
		//read()读取下一个byte,如果到达最后返回-1
		fis.read();
		//关闭流,释放资源
		fis.close();
	}
	
	//FileOutputStream,写入
	public static void testOPS(File file) throws IOException {
		if (file.exists()) {
			//boolean true,true从末尾写入
			FileOutputStream fos = new FileOutputStream(file,true);
			String content = "haha--hehe--heihei--xixi";
			fos.write(content.getBytes());
			//
			//关闭流,释放资源
			fos.close();
		}
	}
	
	public static void main(String[] args) throws IOException {
		// 获取文件
		File file = new File("H:" + File.separator + "workspace3" + File.separator + "io" + File.separator + "test.txt");
		//FileOutputStream,写入文件
		FileIO.testOPS(file);
		//FileInputStream,读取文件
		FileIO.testFIS(file);
	}
}

-随机访问文件

随机读写文件的方法是设定一个pointer,相当于一个指针,可以设定从pointer的位置开始读/写。

RandomAccessFile.write()可以向文件中随机写入文件,使用FileIO,或者是FileWR进行写入时,可以在构造方法中传入true参数,这样可以从文件末尾写入,不会覆盖文件原来内容。如果要在随机访问文件时,不覆盖原内容,可以设置pointer为文件长度,这样即可从末尾开始写入。

public class RandomAccess {

	public static void randomAccessFile() throws IOException {
		File file = new File("H:" + File.separator + "workspace3" + File.separator + "io" + File.separator + "test4.txt");
		//创建文件,rw读写,r只读,rws,rwd
		RandomAccessFile raf = new RandomAccessFile(file, "rw");
		String str = "haha hehe heihei xixi 张柏芝 陈冠希 谢霆锋 1 2 3";
		//写入,写入byte数组不会中文乱码,写入string出现乱码
		raf.write(str.getBytes());
		//文件长度
		System.out.println("file-length::"+raf.length());
		//设置pointer
		raf.seek(10);
		//获取pointer
		System.out.println("point ::"+raf.getFilePointer());
		byte[] content = new byte[1024];
		//从pointer位置开始读取
		raf.read(content);
		System.out.println("content:::"+new String(content));
		//读取文件后的pointer位置
		System.out.println(raf.getFilePointer());
	}

	public static void main(String[] args) throws IOException {
		RandomAccess.randomAccessFile();
	}
}

·转换流

FileWriter/FileReader并非直接继承自Writer/Reader,而是继承自InputerStreamReader/OutputStreamWriter。

InputerStreamReader/OutputStreamWriter为转换流,可以将字节流转换为字符流

在二者源码中的说明是:OutputStreamWriter is bridge from character stream to byte stream.(是从字符流到字节流的桥梁)

这里的类结构设计还是有些巧妙的:因为InputStreamReader继承了Reader,所以在InputStreamReader的构造方法中直接super(),就可调用Reader的构造方法,创建一个Reader出来,这样就完成了字节流到字符流的转换。这样的类关系也决定了只能由字节流转换为字符流。

//字节流转换为字符流
public class TransIO {
	public static void transInput(File file) throws IOException {
		InputStream fis = new FileInputStream(file);
		//outputStream --> Writer:
		Reader fr = new InputStreamReader(fis);
	}
	
	public static void transOutput(File file) throws IOException {
		FileOutputStream fos = new FileOutputStream(file);
		//outputStream --> Writer
		Writer fw = new OutputStreamWriter(fos);
	}
	
	public static void main(String[] args) throws IOException {
		File file = new File("d:/test.txt");
		TransIO.transInput(file);
		TransIO.transOutput(file);
	}
}

·String媒介

提供对string的IO操作,感觉有点鸡肋。

-StringWriter/StringReader

public class StringRW {

	public static void testStringWriter() {
		//StringWriter对象sw存放内容
    		StringWriter sw = new StringWriter();
		//写入
		sw.write("hahaha");
		sw.append("c");
		//将sw中内容以StringBuffer输出
		System.out.println(sw.getBuffer());
		//将sw中内容以String输出
		System.out.println(sw.toString());
	}
	
	public static void TestStringReader() throws IOException {
		String str = "abcd";
		StringReader sr = new StringReader(str);
		char[] strValue = new char[100]; 
		//将字符串内容读取到char[]
		sr.read(strValue);
		System.out.println(strValue[0]);
		//将字符串内容读取到stringBuffer
		//省略.....
	}
	
	public static void main(String[] args) {
		StringRW.testStringWriter();
		try {
			StringRW.TestStringReader();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

·管道媒介

pipe管道是用于线程之间的读写。在线程之间进行读写时,需要建立input和output流的连接(connection),否则报异常:

java.io.IOException: Pipe not connected

注意:在PipedOutStream调用write()方法进行写入时,应当选择write(byte[] b)方法,其他方法可能会造成中文乱码问题。

public class PipedIO {
	public static void main(String[] args) throws IOException {
		PipedInputStream pis = new PipedInputStream();
		PipedOutputStream pos = new PipedOutputStream();
		//input/output管道建立连接
		pis.connect(pos);
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					pos.write("hello".getBytes());
				} catch (IOException e) {
					e.printStackTrace();
				}finally {
					try {
						pos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		});

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				int data;
				try {
					data = pis.read();
					while (data != -1) {
						System.out.print((char) data);
						data = pis.read();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}finally {
					try {
						pis.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		});
		t1.start();
		t2.start();
	}
}

·Buffered流

在对流进行写入时提供一个buffer来提高IO效率。在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都是一个字节一个字节操作的,而BufferedInputStream在其内部提供了一个buffer,在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操作效率要高的多,特别是进程磁盘IO和对大量数据进行读写的时候。

不同媒介的流都可以通过Buffered流转换为使用Buffer的流。

另外BufferReader额外提供readline()方法读取一行。

//File字符流转换
BufferedReader bd = new BufferedReader(new FileReader(file));
bd.readline();    //读取一行,返回string
BufferedWriter bw = new BufferedWriter(new FileWriter(file));

//File字节流转换
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream(file));

在close()之前调用flush()方法:

flush()在源码中的说明:

Flushes the stream.  If the stream has saved any characters from the various write() methods in a buffer, write them immediately to their intended destination. 

flush流,如果流已经通过多个write()保存了内容在buffer中,立即将内容写入到目标中

flush()意思是把缓冲区的内容强制的写出。主要用在IO中,即清空缓冲区数据,一般在读写流(stream)的时候,数据是先被读到了内存(buffer)中,再把数据写到文件中,当你数据读完的时候不代表你的数据已经写完了,因为还有一部分有可能会留在内存这个缓冲区中。这时候如果你调用了close()方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭读写流之前先flush()。

flush()也只有在buffered流中使用才有意义。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值