Java 流模型 ----(上)

目录

Java 流模型

字节流

文件的拷贝

byte[]缓存的方式拷贝文件

实现文件夹的拷贝和移动

字符流

文件节点流

内存数组节点流

内存字串流

 


Java 流模型

主要目的:屏蔽具体实现的区别 , 使用统一的方法进行编程。
 

字节(Byte)是计算机信息技术用于计量存储量的一种计量单位,通常情况下一字节等于八位。

字符 是指计算机中使用的字母、数字、字和符号。

不同编码里,字符和字节的对应关系不同:

ASCII码:一个英文字母(不分大小写)占一个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数。换算为十进制 ,最小值-128,最大值127。如一个ASCII码就是一个字节。

Unicode编码:把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。

UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节。这里的关系是,UTF-8是Unicode的实现方式之一。

java采用的编码是unicode编码;

 

字节流

  • 父类InputStreamOutputStream。
  • 一次一字节的操作方式,一般用于声音、图像、视频之类的二进制文件。

FileInputStream

该流用于从文件读取数据,它的对象可以用关键字 new 来创建。有多种构造方法可用来创建对象。

FileOutputStream

该类用来创建一个文件并向文件中写数据

如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件

可以使用字符串类型的文件名来创建一个输入流对象(输出流对象)来读取文件:

InputStream f = new FileInputStream("C:/java/hello");

也可以使用一个文件对象来创建一个输入流对象(输出流对象)来读取文件。我们首先得使用 File() 方法来创建一个文件对象:

File f = new File("C:/java/hello");

InputStream out = new FileInputStream(f);

文件的拷贝

package IO;

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

public class D15 {
	public static void main(String[] args) throws IOException {
	        //while(true) { 无限循环一直往里面写 及时关闭
		// try/resource的写法,会自动执行关闭操作,但是要求实现closeable接口
		try (OutputStream a = new FileOutputStream("C:\\Users\\苑\\Desktop\\JAVA_DY/copyYuan.txt", true);
				InputStream b = new FileInputStream("C:\\Users\\苑\\Desktop\\JAVA_DY/Yuan.txt");) {
			int kk = 0;
			while ((kk = b.read()) > -1) {// 由于是一次读取一字节的操作,所以在操作输出时会有问题,但是文件拷贝不会有任何问题
				a.write(kk);
			}
		}
	}
}
//}

byte[]缓存的方式拷贝文件

上面的方法采用的是一次一字节的操作方法,效率较低,可以考虑引入byte[]缓存的方式提高执行效率。

package IO;

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

public class D16 {
	public static void main(String[] args) throws IOException {

		// try/resource的写法,会自动执行关闭操作,但是要求实现closeable接口
		try (OutputStream a = new FileOutputStream("C:\\Users\\苑\\Desktop\\JAVA_DY/copyYuan.txt", true);
				InputStream b = new FileInputStream("C:\\Users\\苑\\Desktop\\JAVA_DY/Yuan.txt");) {
			int kk = 0;
			byte[] aa = new byte[8192];// 返回值是读取的字节数,最多8192字节,但是 实际上并不一定读取8192字节
			while ((kk = b.read(aa)) > -1) {// 由于是一次读取一字节的操作,所以在操作输出时会有问题,但是文件拷贝不会有任何问题
				a.write(aa, 0, kk); // 把byte[]类型aa写出从0到kk的内容
				String ss = new String(aa, 0, kk);// 主要解决多字节的字符组装问题
				System.out.println(ss);// 输出到面板了
			}
		}
	}
}

实现文件夹的拷贝和移动

文件夹的深度无法提前预知,所以这里采用递归调用的方式进行操作
package IO;

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

public class D17 {// 实现 source路径文件夹 拷贝转移到 target(目标)文件夹
	private static String source; // 静态属性
	private static String target;

	public static void main(String[] args) throws Exception {
		source = "C:\\Users\\苑\\Desktop\\JAVA_DY\\JAVA2\\DYsource";// 这个路径是存在的
		target = "C:\\Users\\苑\\Desktop\\JAVA_DY\\JAVA2\\DYtarget";// 这个路径靠mkdirs()方法创建
		File a = new File(source);
		copy(a);

	}

	public static void copy(File ff) throws Exception {
		if (ff != null && ff.exists()) {
			if (ff.isDirectory()) {
				String path = ff.getAbsolutePath();// 因为时静态属性后面子目录还要用所以这样给新的对象
				// String类replace() 方法通过用 newChar 字符替换字符串中出现的所有 oldchChar 字符,并返回替换后的新字符串
				String newPath = path.replace(source, target);// 把path字符串里面的source全部替换成target
				File t = new File(newPath);// 放的target字符串路径
				if (!t.exists())// 目标target目录不存在时用mkdirs方法
					t.mkdirs();
				// mkdir()创建此抽象路径名称指定的目录(及只能创建一级的目录,且需要存在父目录)
				// mkdirs()创建此抽象路径指定的目录,包括所有必须但不存在的父目录。(及可以创建多级目录,无论是否存在父目录)
				File[] aa = ff.listFiles();// aaFile数组存放下一级文件目录路径
				if (aa != null && aa.length > 0) {
					for (File x : aa) {
						copy(x);// 对每个子目录循环遍历调用copy方法
					}
				}
			} else if (ff.isFile()) {
				String path = ff.getAbsolutePath();
				String newPath = path.replace(source, target);// 把path字符串里面的source全部替换成target,path遍历深就会变长,前面替换,后面的路径就在新的target里
				try (InputStream is = new FileInputStream(ff); OutputStream os = new FileOutputStream(newPath);) {
					byte[] b = new byte[8192];
					int len = 0;
					while ((len = is.read(b)) > -1) {
						os.write(b, 0, len);
					}

				}
			}

		}

	}
}

字符流

一次操作一个字符 一般用于操作文本文件,注意word文档不是字符文件 。

FileReader
  • 用于操作文件,属于节点流;
  • 读取指定文件并在控制台上进行显示。
FileWriter
  • 用于操作文件 new FileWriter(String fileName) ;
  • new FileWriter(String fileName, boolean append) 默认覆盖清空在写,boolean表示是否追加,true就加在原本的内容后面。
package IO;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class D18 {
	public static void main(String[] args) throws IOException {
		File a = new File("C:\\Users\\苑\\Desktop\\JAVA_DY/Yuan.txt");
		if (a.exists()) {
			try (Reader aa = new FileReader(a);) {
				int cc = 0;
				while ((cc = aa.read()) != -1) {// char类型到整型
					System.out.print((char) cc);// 必须强转为char输出到控制台不然为数字
				}

			}
		} else {
			System.out.println("该文件不存在!");
		}
	}
}
package IO;

import java.io.*;

public class D19 {
	public static void main(String[] args) throws IOException {
		File a = new File("C:/Users/苑/Desktop/JAVA_DY/Yuan.txt");
		if (a.exists()) {
			try (   Reader aa = new FileReader(a);
					Writer bb = new FileWriter("C:/Users/苑/Desktop/JAVA_DY/copyYuan.txt", true);) {
				int cc = 0;
				char[] dd = new char[8192]; // 按照字符读取的
				while ((cc = aa.read(dd)) != -1) {
					System.out.print((char) cc);
					bb.write(dd, 0, cc);
				}

			}
		} else {
			System.out.println("文件不存在!");
		}

	}
}
  • 一般在使用中,如果读取数据使用字节流,则写出数据采用的也是字节流;不建议混用,除非引入桥接流;
  • 一般不使用单字节或者单字符的操作方法,使用数组;
  • 注意:try(){}是推荐写法,否则应该使用try{}finally{}结构保证流的关闭;
  • 针对二进制文件不建议使用字符流,建议使用字节流进行操作,否则有可能拷贝文件出现问题;
  • 如果针对文本文件则建议使用字符流,因为编码使用比较方便

文件节点流

FileInputStream FileOutputStream 文件字节流,是一种节点流。
  • 文件字节输入流的构造方法:FileInputStream("文件名称"),如果文件不存在则FileNotFoundException ;FileInputStream(File)。
  • 文件字节输出流的构造方法FileOutputStream(“文件名称”)  如果文件不存在则新建文件,如果文件存在则覆盖文件内容。
  • FileOutputStream(String name文件名称, boolean append是否采用追加方式)。
  • FileReaderFileWriter类似。

内存数组节点

如果文本则使用char[],如果二进制则使用byte[] 。
构造器方法 :CharArrayReader(char[] buf) 其中 char[] 就是数据的来源,也就是说 Reader 就是从 char[] 中读取数据:
 
CharArrayRead(char[] buf, int offset, int length)。
CharArrayWriter 用于实现向一个字符数组中写入数据,这个数组可以自动调整大小。
ByteArrayInputStream ByteArrayOutputStream CharArrayReader 以及 CharArrayWriter 类似,支持操作的 内容不同而已,操作 byte[] char[]。
 

char数组中读取数据

package IO;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;

public class D20 {
	public static void main(String[] args) throws IOException {
		String a = "我还年轻,吃苦趁现在!aaaa";
		Reader b = new CharArrayReader(a.toCharArray());
		int kk = 0;
		while ((kk = b.read()) != -1) {
			System.out.print((char) kk);
		}
		b.close();

	}
}

从一个文件中读取内容并写入到char[]

package IO;

import java.io.CharArrayWriter;
import java.io.FileReader;
import java.io.Reader;
import java.io.Writer;
//从一个文件中读取内容并写入到char[]中
public class D21 {
	public static void main(String[] args) throws Exception {
		Reader r = new FileReader("C:/Users/苑/Desktop/JAVA_DY/Yuan.txt"); 
		Writer w = new CharArrayWriter();// 实际上就是一个writer,向CharArrayWriter写出数据,实际上会自动写入一个相关联的char数组中。
		int cc;
		while ((cc = r.read()) != -1) {
			w.write(cc);
		}
		r.close();
		w.close(); 
		char[] arr = ((CharArrayWriter) w).toCharArray();//返回char类型 不是char数组 这是CharArrayWriter中的特殊方法
		System.out.println(arr);
	}
}

内存字串流

  • StringReader用于从一个字串String中读取数据;
  • StringWriter用于给一个StringBuffer中写入数据,实现一个可变长的字串。
package IO;

import java.io.Reader;
import java.io.StringReader;

public class D22{
	public static void main(String[] args) throws Exception {
		String str = "別説了,注定的!gan";
		Reader r = new StringReader(str);
		int kk;
		while ((kk = r.read()) != -1) {
			System.out.print((char) kk);
		}
		r.close();
	}
}

键盘录入内容,并缓存在内存中,输入quit表示输入完成,输入完成后再在控制台上显示所有输入的内容

package IO;

import java.io.StringWriter;
import java.io.Writer;
import java.util.Scanner;
//键盘录入内容,并缓存在内存中,输入quit表示输入完成,输入完成后再在控制台上显示所有输入的内容
public class D23 {
	public static void main(String[] args) throws Exception {
		Scanner sc = new Scanner(System.in);
		Writer w = new StringWriter();
		int counter = 0;
		while (true) {
			String str = sc.nextLine();
			if ("quit".equals(str))
				break;
			w.write("第" + (++counter) + "次输入为:" + str + "\n");//缓存在内存中
		}
		w.close();
		StringBuffer sb = ((StringWriter) w).getBuffer();//提供getBuffer方法获得缓存的字符串
		System.out.println(sb);
	}

}
/*
yuan
da
quit
第1次输入为:yuan
第2次输入为:da
*/
  • 读写文件 :使用节点流FileInputStream/FileOutputStreamFileReader/FileWriter
  • 操作文本文件 :建议使用FileReader/FileWriter
  • 如果操作二进制文件建议使用 FileInputStream/FileOutputStream;
  • 需要建立缓冲区(建立临时文件的方式效率低),可以考虑使用内存节点,例如

        CharArrayReader/CharArrayWriterStringReader/StringWriter和;

        ByteArrayInputStream/ByteArrayOutputStream ;

  • 如果需要一个二进制缓冲区可以使用ByteArrayInputStream/ByteArrayOutputStream
  • 如果需要一个字符缓存可以使用CharArrayReader/CharArrayWriterStringReader/StringWriter;
  • 如果数据量不是特别大使用CharArrayReader/CharArrayWriter更为方便;
  • 如果数据量大而且可能需要直接操作缓冲区则使用StringReader/StringWriter;
  • StringWriter中提供了方法getBuffer():StringBuffer

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值