[疯狂Java]I/O:字节流、字符流

!!Java的字节流和字符流的操作方式非常相似,方法和参数的共同点非常多,因此就按照输入流和输出流来讲,在输入流和输出流中再细分出字节流和字符流;


1. 输入流中的字节流和字符流:

    1) InputStream和Reader分别代表输入流的字节流和字符流;

    2) 这两个类是所有输入流的抽象基类,其本身并不能作为实例对象来进行操作,但是它们是所有输入流的模板,所有输入流都应包含其中的方法;

    3) 输入流三大读取数据的方法:byte版本的属于InputStream,char版本的属于Reader,InputStream的一个单位是字节,Reader的一单位是一个字符(即2字节)

         i. int read(); // 从输入流中读取一个单位,直接返回读取的单位(byte和char都可以直接转换成int)

         ii. int read(byte[] b/char[] cbuf); // 从输入流中读取b.length/cbuf.length个单位到b/cbuf数组中,返回实际读取了多少个单位

         iii. int read(byte[] b/char[] cbuf, int off, int len); // 从输入流中读取len个单位到b/cbuf中,并且是从数组的off位置开始写

!!上面三个方法都用返回-1表示流的结束(相当于C语言的EOF);

    4) 输入流用完后应该及时关闭资源:void close();

         i. 和JDBC的数据库连接资源一样,I/O资源同样也不属于内存里的资源,一次你垃圾回收机制无法自动回收该资源;

         ii. 因此需要手动调用close方法来关闭,否则就会导致资源泄漏;

         iii. 但是在Java7之后,像JDBC、I/O资源等都实现了AutoCloseable接口,因此都可以通过自动关闭的try语句来关闭这些资源;

    5) 实际中不能直接用InputStream和Reader创建实例进行操作,因为它们都是抽象基类,这里就简单介绍一下最常用的两者的实现类FileInputStream和FileReader两个节点流:

         构造器:FileInputStream/FileReader(String name/File file);  // 可以利用文件名或者文件节点直接构造

    6) 示例1:FileInputStream用close关闭

public class Test {
	
	public static void print(String s) {
		System.out.println(s);
	}
	
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("src\\com\\lirx\\Test.java"); // 使用文件名构造节点流
		byte[] buf = new byte[1024];
		int hasRead = 0;
		while ((hasRead = fis.read(buf)) > 0) {
			print(new String(buf, 0, hasRead));
		}
		fis.close();
	}

}
    7) 示例2:FileReader用try语句自动关闭

public class Test {
	
	public static void print(String s) {
		System.out.println(s);
	}
	
	public static void main(String[] args) throws IOException {
		try (FileReader fr = new FileReader(new File("src\\com\\lirx\\Test.java"))) { // 直接用节点创建流
			char[] cbuf = new char[128];	// try语句自动关闭I/O流
			int hasRead = 0;
			while ((hasRead = fr.read(cbuf)) > 0) {
				print(new String(cbuf, 0, hasRead));
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

}


2. 输出流中的字节流和字符流:

    1) OutputStream和Writer分别是所有输出字节流和字符流的抽象基类;

    2) 其向输出流中写入数据的三大方法:b/byte是字节流版本,c/char是字符流版本

         i. void write(int b/int c);  // 向输出流中写入一单位数据

         ii. void write(byte[] buf/char[] cbuf);  // 将数组中的数据全部写入输出流,单位个数是buf.length/cbuf.length

         iii. void write(byte[] buf/char cbuf, int off, int len);  // 将数组中从off开始的len个单位写入输出流

    3) 对于Writer,由于是字符流,因此可以直接用String来代替字符数组来向流中写数据,因此还有两个Writer的write版本:只属于Writer对象

         i. void write(String str); // 将str插入到输出流中

         ii. void write(String str, int off, int len); // 将str中从off开始的len个字符插入到输出流中

    4) 这里简单介绍以下OutputStream和Writer的最常用的实现类,还是文件输出流,分别是FileOutputStream和FileWriter,其构造器和输入流一样(两个版本,一个是直接利用文件节点构造,另一个是以文件名来构造):FileOutputStream/FileWriter(String name/File file);

    5) 两者同样可以利用close方法来关闭,或者直接用try语句自动关闭(实现了AutoCloseable接口了);

    6) 示例1:字节流实现文件复制(显式close关闭)

public class Test {
	
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("src\\com\\lirx\\Test.java");
		FileOutputStream fos = new FileOutputStream("src\\com\\lirx\\Test1.java");
		
		byte[] buf = new byte[128];
		int hasRead = 0;
		while ((hasRead = fis.read(buf)) > 0) {
			fos.write(buf, 0, hasRead);
		}
		
		fis.close();
		fos.close();
	}

}
    7) 示例2:字符流直接写数据到一个文件中(使用try语句关闭资源)

public class Test {
	
	public static void main(String[] args) throws IOException {
		try (FileWriter fw = new FileWriter(new File("poem.txt"))) {
			fw.write("hello!\r\n");
			fw.write("good morning!\r\n");
		}
	}

}
!!在Windows下换行是\r\n,而在Linux下直接\n就行了;


3. 输入流允许移动指针:

    1) 当你对流进行读写操作时其实底层维护这一个指针指向你正在操作的数据单位;

    2) 对于输入流,由于程序需要使用输入流中的数据,因此可能需要反复读取其中的数据,但如果输入流不允许移动指针的话那就必须自己开辟一段内存来缓存输入流中的数据,这样比较浪费内存空间,如果可以像访问普通数组那样访问输入流中的数据缓存区那该多方便省事啊;

    3) Java提供了两种移动输入流指针的方法:

         i. mark&reset:mark会在当前位置做一个标记,然后就正常向后读取就行了,一旦调用reset就会将指针移动最近一次标记处;

!!但是该方法支持的不是很好,目前就暂时不支持这一功能!

!!可以调用InputStream和Reader的markSupported来查看这一功能是否支持:boolean markSupported();

         ii. 略过n个单位:long skip(long n);  // 该方法支持!可以正常使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值