(一)字节流
一、InputStream
案例:读取"c:/a.txt"文件中的所有内容并在控制台显示出来。
思路:
流是Java中的一类对象,要打开流其实就是创建具体流的对象,由于是读取硬盘上的文件,应该使用输入流。所以找到了InputStream类,但是InputStream是抽象类,需要使用它的具体实现类来创建对象就是FileInputStream。通过new调用FileInputStream的构造方法来创建对象。发现FileInputStream的构造方法需要指定文件的来源。查看构造方法,可以接受字符串也可以接受File对象。我们通过构建File对象指定文件路径。当完成流的读写时,应该通过调用close方法来关闭它,释放掉十分有限的操作系统资源.如果一个应用程序打开了过多的流而没有关闭它们,那么系统资源将被耗尽。
(1)输入流读取方式1
read方法():一次读取一个字节,读到文件末尾返回-1。仔细查看api文档发现read方法如果读到文件的末尾会返回-1。那么就可以通过read方法的返回值是否是-1来控制我们的循环读取。
private static void showContent(String path) throws IOException {
// 打开流
FileInputStream fis = new FileInputStream(path);
int len;
while ((len = fis.read()) != -1) {
System.out.print((char) len);
}
// 使用完关闭流
fis.close();
(2)输入流读取方式2
使用read(byte[] b) 方法:使用缓冲区(关键是缓冲区大小的确定)。使用read方法的时候,流需要读一次就处理一次,可以将读到的数据装入到字节数组中,一次性的操作数组,可以提高效率。
private static void showContent2(String path) throws IOException {
// 打开流
FileInputStream fis = new FileInputStream(path);
// 通过流读取内容
byte[] byt = new byte[5];
int len = fis.read(byt);
for (int i = 0; i < byt.length; i++) {
System.out.print((char) byt[i]);
}
// 使用完关闭流
fis.close();
}
(3)输入流读取方式3
使用read(byte[] b,int off,int len):b显然是一个byte类型数组,当做容器来使用;off,是指定从数组的什么位置开始存字节;len,希望读多少个。其实就是把数组的一部分当做流的容器来使用。告诉容器,从什么地方开始装要装多少。
private static void showContent3(String path) throws IOException {
// 打开流
FileInputStream fis = new FileInputStream(path);
// 通过流读取内容
byte[] byt = new byte[1024];
// 从什么地方开始存读到的数据
int start = 5;
// 希望最多读多少个(如果是流的末尾,流中没有足够数据)
int maxLen = 6;
// 实际存放了多少个
int len = fis.read(byt, start, maxLen);
for (int i = start; i < start + maxLen; i++) {
System.out.print((char) byt[i]);
}
// 使用完关闭流
fis.close();
}
补充:skip方法,skip(long n),参数跟的是要跳过读取的字节数。
总结:读取文件所有内容:i)可以使用普通的read方法,一次读一个字节直到读到文件末尾;ii)为了提高效率可以使用read(byte[] byt)方法,就是所谓的使用缓冲提高效率。
二、OutputStream
(1)输出流写出方式1
使用write(int b)方法,一次写出一个字节。在C盘下创建a.txt文本文件
import java.io.FileOutputStream;
import java.io.IOException;
public class IoTest2 {
public static void main(String[] args) throws IOException {
String path = "c:\\a.txt";
writeTxtFile(path);
}
private static void writeTxtFile(String path) throws IOException {
// 1:打开文件输出流,流的目的地是指定的文件
FileOutputStream fos = new FileOutputStream(path);
// 2:通过流向文件写数据
fos.write('j');
fos.write('a');
fos.write('v');
fos.write('a');
// 3:用完流后关闭流
fos.close();
}
}
当c盘下的a.txt不存在会怎么样:当文件不存在时,会自动创建一个,但是创建不了多级目录。
注意:使用write(int b)方法,虽然接收的是int类型参数,但是write的常规协定是:向输出流写入一个字节。要写入的字节是参数 b的八个低位。b的24个高位将被忽略。
(2)输出流写出方式2使用write(byte[] b):使用缓冲,提高效率,将 b.length 个字节从指定的 byte 数组写入此输出流中。
前面案例使用OutputStram 的write方法,一次只能写一个字节。使用缓冲,根据字节输入流的缓冲原理,可以将数据保存在字节数组中,通过操作字节数组来提高效率。
如何将字节数据保存在字节数组中:以字符串为例,”hello , world”如何转为字节数组?显然字符串的getBytes方法即可。
public class IoTest2 {
public static void main(String[] args) throws IOException {
String path = "c:\\a.txt";
writeTxtFile(path);
}
private static void writeTxtFile(String path) throws IOException {
// 1:打开文件输出流,流的目的地是指定的文件
FileOutputStream fos = new FileOutputStream(path);
// 2:通过流向文件写数据
byte[] byt = "java".getBytes();
fos.write(byt);
// 3:用完流后关闭流
fos.close();
}
}
a.txt文本文件发现上述程序每运行一次,老的内容就会被覆盖掉。如何不覆盖已有信息,往a.txt里追加信息:FileOutputStream类中的构造方法中有一个构造可以实现追加的功能FileOutputStream(File file, boolean append) 第二个参数,append如果为true,则将字节写入文件末尾处,而不是写入文件开始处。
三、字节流文件拷贝(1)字节流文件拷贝实现1
读一个字节写一个字节:read 和write
public class IoTest3 {
public static void main(String[] args) throws IOException {
String srcPath = "c:\\a.txt";
String destPath = "d:\\a.txt";
copyFile(srcPath, destPath);
}
public static void copyFile(String srcPath, String destPath)
throws IOException {
// 打开输入流,输出流
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
// 读取和写入信息
int len = 0;
while ((len = fis.read()) != -1) {
fos.write(len);
}
// 关闭流
fis.close();
fos.close();
}
}
字节流可以操作所有的文件,但需要很长时间,特别是拷贝音频和视频文件:因为每次读一个字节再写一个字节效率很低。很显然这样效率低下的操作不是我们想要的,可以使用缓冲区来提高程序的效率。
(2)字节流文件拷贝实现2public static void copyFile2(String srcPath, String destPath)
throws IOException {
// 打开输入流,输出流
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
// 读取和写入信息
int len = 0;
// 使用字节数组,当做缓冲区
byte[] byt = new byte[1024];
while ((len = fis.read(byt)) != -1) {
fos.write(byt);
}
// 关闭流
fis.close();
fos.close();
}
在这个方法中,我们使用的容器是重复使用的,新的数据会覆盖掉老的数据。如果在最后一次读文件时容器没有装满,则再次进行拷贝得到的结果就会出现新老数据并存的现象,使得拷贝文件与源文件之间出现差异。使用FileOutputStream的write(byte[] b, int off, int len)可以避免这个错误:b是容器,off是从数组的什么位置开始,len是获取的个数,容器用了多少就写出多少。
四、字节流的异常处理使用try{} catch(){}finally{}语句:try中放入可能出现异常的语句,catch是捕获异常对象,fianlly是一定要执行的代码。保证close()语句能够执行以释放内存。
文件拷贝的异常处理:
public static void copyFile(String srcPath, String destPath) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcPath);
fos = new FileOutputStream(destPath);
byte[] byt = new byte[1024 * 1024];
int len = 0;
while ((len = fis.read(byt)) != -1) {
fos.write(byt, 0, len);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
注意:最后的close代码可能会有问题:两个close。如果第一个close方法出现了异常,并抛出了运行时异常,那么程序还是停止了,下面的close方法就没有执行到。
为了保证close的执行,将第二个放到fianlly中即可。
public class IoTest5 {
public static void main(String[] args) throws IOException {
String srcPath = "c:\\a.mp3";
String destPath = "d:\\copy.mp3";
copyFile(srcPath, destPath);
}
public static void copyFile(String srcPath, String destPath)
throws IOException {
// 打开输入流,输出流
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
// 使用缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 读取和写入信息
int len = 0;
while ((len = bis.read()) != -1) {
bos.write(len);
}
// 关闭流
bis.close();
bos.close();
}
}
(二)字符流
字节流处理字符信息时不方便,此时使用字符流。(例:一个中文占两个字节,此时不能一个字节一个字节地进行读入)。
一、Reader
public class IoTest1_Reader {
public static void main(String[] args) throws Exception {
String path = "c:/a.txt";
// readFileByInputStream(path);
readFileByReader(path);
}
/**
* 使用字节流读取文件内容
*
* @param path
*/
public static void readFileByInputStream(String path) throws Exception {
InputStream in = new FileInputStream(path);
int len = 0;
while ((len = in.read()) != -1) {
System.out.print((char) len);
}
in.close();
}
/**
* 使用字符流读取文件内容
*/
public static void readFileByReader(String path) throws Exception {
Reader reader = new FileReader(path);
int len = 0;
while ((len = reader.read()) != -1) {
System.out.print((char) len);
}
reader.close();
}
}
二、Writer
Writer是抽象类无法创建对象,但可以使用其子类FileWriter。
(1)将文本数据存储到一个文件中
public class IoTest2_Writer {
public static void main(String[] args) throws Exception {
String path = "c:/ab.txt";
writeToFile(path);
}
/**
* 写指定数据到指定文件中
*
*/
public static void writeToFile(String path) throws Exception {
Writer writer = new FileWriter(path);
writer.write('中');
writer.write("世界".toCharArray());
writer.write("中国");
writer.close();
}
}
(2)追加文件
默认的FileWriter方法新值会覆盖旧值,想要实现追加功能需要,使用如下构造函数创建输出流 append值为true即可:FileWriter(String fileName, boolean append);和FileWriter(File file, boolean append)。
(3)flush方法
如果没有close(),则程序需要使用flush方法. 刷新该流的缓冲(否则有可能没有内容写入)。只要指定close()方法就不用再flush方法:因为close也调用了flush方法。
private static void writeFileByWriter(File file) throws IOException {
FileWriter fw = new FileWriter(file);
fw.write('新');
fw.flush();
fw.write("中国".toCharArray());
fw.write("世界你好!!!".toCharArray());
fw.write("明天");
// 关闭流资源
//fw.close();
}
三、字符流拷贝文件
(1)字符流拷贝文件实现1
public static void main(String[] args) throws Exception {
String path1 = "c:/a.txt";
String path2 = "c:/b.txt";
copyFile(path1, path2);
}
/**
* 使用字符流拷贝文件
*/
public static void copyFile(String path1, String path2) throws Exception {
Reader reader = new FileReader(path1);
Writer writer = new FileWriter(path2);
int ch = -1;
while ((ch = reader.read()) != -1) {
writer.write(ch);
}
reader.close();
writer.close();
}
这一实现一次读一个字符就写一个字符,效率不高。可以把读到的字符放到字符数组中,再一次性的写出,以提高效率。
(2)字符流拷贝文件实现2public static void main(String[] args) throws Exception {
String path1 = "c:/a.txt";
String path2 = "c:/b.txt";
copyFile(path1, path2);
}
public static void copyFile3(String path1, String path2) throws Exception {
Reader reader = new FileReader(path1);
Writer writer = new FileWriter(path2);
int ch = -1;
char [] arr=new char[1024];
while ((ch = reader.read(arr)) != -1) {
writer.write(arr,0,ch);
}
reader.close();
writer.close();
}
字节流可以拷贝视频和音频等文件,但字符流不可以。原因:计算机中的所有信息都是以二进制形式进行的存储,图片中的也都是二进制。在读取文件的时候字符流自动对这些二进制按照码表进行了编码处理,但是图片本来就是二进制文件,不需要进行编码。有一些巧合在码表中有对应,就可以处理,并不是所有的二进制都可以找到对应的。信息就会丢失。所以字符流只能拷贝以字符为单位的文本文件。
四、字符流的异常处理
public static void main(String[] args) throws Exception {
String path1 = "c:/a.txt";
String path2 = "c:/b.txt";
copyFile2(path1, path2);
}
/**
* 使用字符流拷贝文件,有完善的异常处理
*/
public static void copyFile2(String path1, String path2) {
Reader reader = null;
Writer writer = null;
try {
// 打开流
reader = new FileReader(path1);
writer = new FileWriter(path2);
// 进行拷贝
int ch = -1;
while ((ch = reader.read()) != -1) {
writer.write(ch);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 关闭流,注意一定要能执行到close()方法,所以都要放到finally代码块中
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
五、
BufferedReader的使用:
public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
}
private static void readFile(String path) throws IOException {
Reader read = new FileReader(path);
BufferedReader br = new BufferedReader(read);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
例子:使用字符流缓冲区拷贝文本文件
public class Demo7 {
public static void main(String[] args) throws IOException {
// 关联源文件
File srcFile = new File("c:\\linux大纲.txt");
// 关联目标文件
File destFile = new File("d:\\linux大纲.txt");
// 实现拷贝
copyFile(srcFile, destFile);
}
private static void copyFile(File srcFile, File destFile)
throws IOException {
// 创建字符输入流
FileReader fr = new FileReader(srcFile);
// 创建字符输出流
FileWriter fw = new FileWriter(destFile);
// 字符输入流的缓冲流
BufferedReader br = new BufferedReader(fr);
// 字符输出流的缓冲流
BufferedWriter bw = new BufferedWriter(fw);
String line = null;
// 一次读取一行
while ((line = br.readLine()) != null) {
// 一次写出一行.
bw.write(line);
// 刷新缓冲
bw.flush();
// 进行换行,由于readLine方法默认没有换行.需要手动换行
bw.newLine();
}
// 关闭流
br.close();
bw.close();
}
}
六、装饰器模式
(1)在读取文件的每一行添加行号:BufferedReader继承Reader对父类进行了功能的增强,因此可以继承BufferedReader重写该类的readLine方法,进行功能的增强。
public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
}
private static void readFile(String path) throws IOException {
Reader read = new FileReader(path);
BufferedReader br = new MyBufferedReader(read);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
class MyBufferedReader extends BufferedReader {
public MyBufferedReader(Reader read) {
super(read);
}
int count;
@Override
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
count++;
return count + ":" + line;
} else {
return null;
}
}
}
(2)在输出的一行前加上引号并添加行号:其实就是一个新类要对原有类进行功能增强,实现步骤如下:
i)在增强类中维护一个被增强的父类引用变量
ii)在增强类的构造函数中初始化i)中的变量
iii)创建需要增强的方法,在刚才方法中调用被增强类的方法,并加以增强
public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
}
private static void readFile(String path) throws IOException {
Reader read = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(read);
BufferedReader br = new MyQutoBufferedReader2(bufferedReader);
br = new MyLineBufferedReader2(br);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
// quotation 引号
class MyQutoBufferedReader2 extends BufferedReader {
private BufferedReader bufferedReader;
public MyQutoBufferedReader2(BufferedReader bufferedReader) {
super(bufferedReader);
this.bufferedReader = bufferedReader;
}
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
return "\"" + line + "\"";
} else {
return null;
}
}
}
class MyLineBufferedReader2 extends BufferedReader {
private BufferedReader bufferedReader;
public MyLineBufferedReader2(BufferedReader bufferedReader) {
super(bufferedReader);
this.bufferedReader = bufferedReader;
}
int count;
@Override
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
count++;
return count + ":" + line;
} else {
return null;
}
}
}
关键性语句:
BufferedReader br = new MyQutoBufferedReader2(bufferedReader);
br = new MyLineBufferedReader2(br);
(三)其他流
一、序列流
(1)合并两个流:使用构造函数SequenceInputStream(InputStream s1, InputStream s2)
private static void testSequenceInputStream() throws IOException {
FileInputStream fis1 = new FileInputStream("c:\\a.txt");
FileInputStream fis2 = new FileInputStream("c:\\b.txt");
SequenceInputStream s1 = new SequenceInputStream(fis1, fis2);
int len = 0;
byte[] byt = new byte[1024];
FileOutputStream fos = new FileOutputStream("c:\\z.txt");
while ((len = s1.read(byt)) != -1) {
fos.write(byt, 0, len);
}
s1.close();
}
(2)合并多个流
public static void testSequenceInputStream() throws Exception {
InputStream in1 = new FileInputStream("c:/a.txt");
InputStream in2 = new FileInputStream("c:/b.txt");
InputStream in3 = new FileInputStream("c:/c.txt");
LinkedHashSet<InputStream> set = new LinkedHashSet<InputStream>();
set.add(in1);
set.add(in2);
set.add(in3);
final Iterator<InputStream> iter = set.iterator();
SequenceInputStream sin = new SequenceInputStream(
new Enumeration<InputStream>() {
@Override
public boolean hasMoreElements() {
return iter.hasNext();
}
@Override
public InputStream nextElement() {
return iter.next();
}
});
FileOutputStream out = new FileOutputStream("c:/z.txt");
for (int b = -1; (b = sin.read()) != -1;) {
out.write(b);
}
sin.close();
out.close();
}
案例:
将map3
歌曲文件进行切割拷贝
并合并:
public class Demo2 {
public static void main(String[] args) throws IOException {
split(new File("c:\\a.mp3"), 10, new File("c:\\"));
System.out.println("切割完毕");
LinkedHashSet<InputStream> hs = new LinkedHashSet<InputStream>();
hs.add(new FileInputStream(new File("c:\\part.1.mp3")));
hs.add(new FileInputStream(new File("c:\\part.2.mp3")));
hs.add(new FileInputStream(new File("c:\\part.3.mp3")));
hs.add(new FileInputStream(new File("c:\\part.4.mp3")));
merage(hs, new File("c:\\merage.mp3"));
System.out.println("合并完毕");
}
private static void merage(LinkedHashSet<InputStream> hs, File dest)
throws IOException {
final Iterator<InputStream> it = hs.iterator();
FileOutputStream fos = new FileOutputStream(dest);
SequenceInputStream seq = new SequenceInputStream(
new Enumeration<InputStream>() {
@Override
public boolean hasMoreElements() {
return it.hasNext();
}
@Override
public InputStream nextElement() {
return it.next();
}
});
byte[] byt = new byte[1024 * 1024];
int len = 0;
while ((len = seq.read(byt)) != -1) {
fos.write(byt, 0, len);
}
seq.close();
fos.close();
}
// 1. 切割文件
/*
* 切割文件,切割份数, 切割后保存路径
*/
private static void split(File src, int count, File dir) throws IOException {
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = null;
byte[] byt = new byte[1024 * 1024];
int len = 0;
for (int i = 1; i <= count; i++) {
len = fis.read(byt);
if (len != -1) {
fos = new FileOutputStream(dir + "part." + i + ".mp3");
fos.write(byt, 0, len);
}
// fos.close();
}
fis.close();
}
}
二、对象的序列化
(1)例子:序列化和反序列化Cat对象
public class Demo3 {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
Cat cat = new Cat("tom", 3);
FileOutputStream fos = new FileOutputStream(new File("c:\\Cat.txt"));
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(cat);
System.out.println(cat);
oos.close();
// 反序列化
FileInputStream fis = new FileInputStream(new File("c:\\Cat.txt"));
ObjectInputStream ois = new ObjectInputStream(fis);
Object readObject = ois.readObject();
Cat cat2 = (Cat) readObject;
System.out.println(cat2);
fis.close();
}
class Cat implements Serializable {
public String name;
public int age;
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat [name=" + name + ", age=" + age + "]";
}
}
例子关键点:
i) 声明Cat类实现了Serializable接口:是一个标示器,没有要实现的方法
ii) 新建Cat对象,新建字节流对象(FileOutputStream)到序列化对象保存在本地文件中
iii) 新建ObjectOutputStream对象,调用writeObject方法序列化Cat对象,writeObject方法会执行两个工作:序列化对象,然后将序列化的对象写入文件中
iv) 反序列化就是调用ObjectInputStream的readObject()方法
v) 异常处理和流的关闭动作要执行。
三、Properties
例子:记录一个程序运行的次数,当满足指定次数时,该程序就不可以再继续运行了,通常可用于软件使用次数的限定。
public static void sysPropList() throws IOException {
Properties prop = System.getProperties();
// prop.list(System.out);// 目的是控制台。
// 需求是:将jvm的属性信息存储到一个文件中。
prop.list(new PrintStream("java.txt"));
}
public static void sysProp() {
Properties prop = System.getProperties();
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
System.out.println(key + ":" + prop.getProperty(key));
}
}
案例:
public static void loadFile() throws IOException {
// 1,创建Properties(Map)对象
Properties prop = new Properties();
// 2.使用流加载配置文件。
FileInputStream fis = new FileInputStream("c:\\qq.txt");
// 3。使用Properties 对象的load方法将流中数据加载到集合中。
prop.load(fis);
// 遍历该集合
Set<Entry<Object, Object>> entrySet = prop.entrySet();
Iterator<Entry<Object, Object>> it = entrySet.iterator();
while (it.hasNext()) {
Entry<Object, Object> next = it.next();
Object key = next.getKey();
Object value = next.getValue();
}
// 通过键获取指定的值
Object object = prop.get("jack");
System.out.println(object);
// 通过键修改值
prop.setProperty("jack", "888888");
// 将集合中的数据写入到配置文件中。
FileOutputStream fos = new FileOutputStream("c:\\qq.txt");
// 注释:
prop.store(fos, "yes,qq");
fos.close();
fis.close();
}
获取记录程序运行次数:
public class Demo6 {
public static void main(String[] args) throws IOException {
int count = 0;
Properties pro = new Properties();
File file = new File("c:\\count.ini");
FileInputStream fis = null;
if (!file.exists()) {
file.createNewFile();
}
fis = new FileInputStream(file);
pro.load(fis);
String str = pro.getProperty("count");
if (str != null) {
count = Integer.parseInt(str);
}
if (count == 3) {
System.out.println("使用次数已到,请付费");
System.exit(0);
}
count++;
System.out.println("欢迎使用本软件" + "你已经使用了:" + count + " 次");
pro.setProperty("count", count + "");
FileOutputStream fos = new FileOutputStream(new File("c:\\count.ini"));
pro.store(fos, "请保护知识产权");
fis.close();
fos.close();
}
}
四、操作基本数据类型的流对象
(1)使用DataInputStream写数据文件
public static void testDataInputStream() throws Exception {
DataOutputStream out = new DataOutputStream(new FileOutputStream(
"c:/a.txt"));
out.writeBoolean(true);
out.writeByte(15); // 0x05 1 个字节
out.writeBytes("abc"); // 0x 0041 2个字节
out.writeChar('X'); // ??
out.writeChars("xyz");
out.writeLong(111);
out.writeUTF("中国");
out.close();
DataInputStream in = new DataInputStream(
new FileInputStream("c:/a.txt"));
System.out.println(in.readBoolean());
System.out.println(in.readByte());
System.out.println(in.readByte());
System.out.println(in.readByte());
System.out.println(in.readByte());
System.out.println(in.readChar());
System.out.println(in.readChar());
System.out.println(in.readChar());
System.out.println(in.readChar());
System.out.println(in.readLong());
System.out.println(in.readUTF());
in.close();
}
(四)编解码
一、字节流读取中文
public class TestIo {
public static void main(String[] args) throws IOException {
readFileByInputStream("c:\\a.txt");
}
private static void readFileByInputStream(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len, "gbk"));
}
}
}
注意:如果指定的编码表和解码表不对应就会出现问题
二、字节流写出中文
需要对字符串进行编码操作后,将得到的二进制内容通过字节流写入到文件中。使用String的getBytes方法,无参数的会使用系统默认的码表进行编码,也可以指定码表。
系统默认编码如下:
public class TestIo {
public static void main(String[] args) throws IOException {
String path = "c:\\test.txt";
writeFileByOutputStream(path, "世界你好");
readFileByInputStream(path);
}
private static void writeFileByOutputStream(String path, String content)
throws IOException {
FileOutputStream fos = new FileOutputStream(path);
// 把字符串进行编码操作,系统默认编码
byte[] bytes = content.getBytes();
// 内容通过字节流写入到文件中。
fos.write(bytes);
fos.close();
}
private static void readFileByInputStream(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = fis.read(buffer)) != -1) {
// 二进制解码,使用系统默认编码
System.out.println(new String(buffer, 0, len));
}
}
}
三、转换流
InputStreamReader将字节流转换为字符流。
测试InputStreamReader:1、专门新建以GBK编码的文本文件。为了便于标识,我们命名为gbk.txt,和以UFT-8编码的文本文件,命名为utf.txt;2、 分别写入汉字”中国”;3、编写测试方法,用InputStreamReader 分别使用系统默认编码,GBK,UTF-8编码读取文件。
public class Demo4 {
public static void main(String[] args) throws IOException {
File file = new File("c:\\a.txt");
File fileGBK = new File("c:\\gbk.txt");
File fileUTF = new File("c:\\utf.txt");
// 默认编码
testReadFile(file);
// 传入gbk编码文件,使用gbk解码
testReadFile(fileGBK, "gbk");
// 传入utf-8文件,使用utf-8解码
testReadFile(fileUTF, "utf-8");
}
// 该方法中nputStreamReader使用系统默认编码读取文件.
private static void testReadFile(File file) throws
IOException {
FileInputStream fis = new FileInputStream(file);
InputStreamReader ins = new InputStreamReader(fis);
int len = 0;
while ((len = ins.read()) != -1) {
System.out.print((char) len);
}
ins.close();
fis.close();
}
// 该方法使用指定编码读取文件
private static void testReadFile(File file, String encod)
throws IOException {
FileInputStream fis = new FileInputStream(file);
InputStreamReader ins = new InputStreamReader(fis, encod);
int len = 0;
while ((len = ins.read()) != -1) {
System.out.print((char) len);
}
ins.close();
}
}
OutputStreamWriter将字节流转换为字符流。
测试OutputStreamWriter :1、分别使用OutputStreamWriter使用系统默认编码、GBK、UTF-8相对应的默认编码文件,GBK编码文件,UTF-8编码文件中写出汉字”中国”;2、在使用上述案例中的readFile方法传入相对应码表读取。
public class TestIo {
public class Demo4 {
public static void main(String[] args) throws IOException {
File file = new File("c:\\a.txt");
File fileGBK = new File("c:\\gbk.txt");
File fileUTF = new File("c:\\utf.txt");
// 写入
// 使用系统默认码表写入
testWriteFile(file);
// 使用gbk编码向gbk文件写入信息
testWriteFile(fileGBK, "gbk");
// 使用utf-8向utf-8文件中写入信息
testWriteFile(fileUTF, "utf-8");
// 读取
// 默认编码
testReadFile(file);
// 传入gbk编码文件,使用gbk解码
testReadFile(fileGBK, "gbk");
// 传入utf-8文件,使用utf-8解码
testReadFile(fileUTF, "utf-8");
}
// 使用系统码表将信息写入到文件中
private static void testWriteFile(File file) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter ops = new OutputStreamWriter(fos);
ops.write("中国");
ops.close();
}
// 使用指定码表,将信息写入到文件中
private static void testWriteFile(File file, String encod)
throws IOException {
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter ops = new OutputStreamWriter(fos, encod);
ops.write("中国");
ops.close();
}
// 该方法中nputStreamReader使用系统默认编码读取文件.
private static void testReadFile(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
InputStreamReader ins = new InputStreamReader(fis);
int len = 0;
while ((len = ins.read()) != -1) {
System.out.print((char) len);
}
ins.close();
}
// 该方法适合用指定编码读取文件
private static void testReadFile(File file, String encod)
throws IOException {
FileInputStream fis = new FileInputStream(file);
InputStreamReader ins = new InputStreamReader(fis, encod);
int len = 0;
while ((len = ins.read()) != -1) {
System.out.print((char) len);
}
ins.close();
}
}