目录
Java 流模型
字节(Byte)是计算机信息技术用于计量存储量的一种计量单位,通常情况下一字节等于八位。
字符 是指计算机中使用的字母、数字、字和符号。
不同编码里,字符和字节的对应关系不同:
ASCII码:一个英文字母(不分大小写)占一个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数。换算为十进制 ,最小值-128,最大值127。如一个ASCII码就是一个字节。
Unicode编码:把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节。这里的关系是,UTF-8是Unicode的实现方式之一。
java采用的编码是unicode编码;
字节流
- 父类InputStream和OutputStream。
- 一次一字节的操作方式,一般用于声音、图像、视频之类的二进制文件。
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文档不是字符文件 。
- 用于操作文件,属于节点流;
- 读取指定文件并在控制台上进行显示。
- 用于操作文件 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("文件名称"),如果文件不存在则FileNotFoundException ;FileInputStream(File)。
- 文件字节输出流的构造方法: FileOutputStream(“文件名称”) 如果文件不存在则新建文件,如果文件存在则覆盖文件内容。
- FileOutputStream(String name文件名称, boolean append是否采用追加方式)。
- FileReader和FileWriter类似。
内存数组节点流
从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/FileOutputStream和FileReader/FileWriter;
- 操作文本文件 :建议使用FileReader/FileWriter;
- 如果操作二进制文件建议使用 FileInputStream/FileOutputStream;
- 需要建立缓冲区(建立临时文件的方式效率低),可以考虑使用内存节点,例如
CharArrayReader/CharArrayWriter、StringReader/StringWriter和;
ByteArrayInputStream/ByteArrayOutputStream ;
- 如果需要一个二进制缓冲区可以使用ByteArrayInputStream/ByteArrayOutputStream;
- 如果需要一个字符缓存可以使用CharArrayReader/CharArrayWriter、StringReader/StringWriter;
- 如果数据量不是特别大使用CharArrayReader/CharArrayWriter更为方便;
- 如果数据量大而且可能需要直接操作缓冲区则使用StringReader/StringWriter;
- StringWriter中提供了方法getBuffer():StringBuffer