文件流、字节流、字符流、缓冲流、转换流、内存流
文件流: 在JAVA 中,文件流负责操作文件,包括读取和写入;
FileInputStream // 文件的字节输入流;
FileOutputStream // 文件的字节输出流;
FileReader // 文件的字符输入流;
FileWriter // 文件的字符输出流;
FileInputStream 和 FileOutputStream的父类分别是InputStream和OutputStream,都是字节流,以面向字节的形式提供IO操作。FileReader 和 FileWriter的父类则是Reader和Writer,都是字符流,字符流以面向字符提供IO操作,同时,字符流兼容Unicode,能够提供更好的国际化支持。
在读取数据时,字节流的数据存储单位是字节,在接收字节流数据时,会新建一个字节类型的数组(byte[])来接收读取的数据;字符流的数据存储单位是字符,在接收字符流数据时,会新建一个字符类组(char[])的数据来接收读取的数据。
InputStream:
InputStream及其子类的作用是用来表示不同数据源输入数据的类,其中封装了用于从数据源中读取数据的操作。这些数据源包括:
InputStream子类:
OutputStream:
OutputStream及其子类的作用是用来表示数据输出将要去向的目标,比如:文件、资源管道、字节数组等。OutputStream也是因不同的目标有不同的子类:
字符流有着和字节流近乎一样的功能,每个字节流api都能在字符流中找到与之相对应的,而且,字符流比字节流有着更好的性能;尽管如此,字符流的设计并不是为了取代字节流,相反,二者同时存在,相辅相成。
Reader 和 Writer及其子类都提供了对Unicode的支持,这是他们和InputStream与OutputStream系拓展最大的不同,详细如下图所示:
字节流和字符流的api对应
Java IO中提供了过滤器:FilterInputStream和FilterOutputstream,用于筛选特定的输入流和输出流。因为FilterInputStream和FilterOutputstream也是自InputStream与OutputStream继承而来,所以他们都可以读写来自InputStream与OutputStream的数据。
FilterInputStream子类:
FilterOutputStream子类:
同样,在Reader 和 Writer中也提供了与之对应的类,详细如下:
文件过滤器 子类
字节流又分字节输入流(InputStream)和字节输出流(OutputStream),分别对应读和写;
字节输入流:FileInputStream,字节输入流的使用案例代码如下:
import java.io.*;
/**
* 案例:使用字节流完成文件拷贝任务。
*/
public class StreamCopyDemo {
public static void main(String[] args) throws Exception {
// 分别创建文件的源对象和目标对象
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
// 创建输入和输出管道
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
// 读取/写出数据
byte[] buffer = new byte[1024]; // 设置每次读取的字节数
int len = -1; // 读取到的字节总数
while ((len = in.read(buffer)) != -1) {
// 写出数据
out.write(buffer, 0, len);
}
// 关闭输入/输出管道
in.close();
out.close();
}
}
字节输入流在读取数据时使用的是read()方法,该方法还有另外的重载方法:
void read(int b);
// 读取单个字节
void read(byte[] b);
// 读取多个字节,并存储到(byte[] b)中
void read(byte[] b, int off, int len);
// 读取多个字节,并存储到(byte[] b)中,从数组b的off索引为止开始存储
字节输出流:FileOutputStream,字节输出流的使用案例代码如下:
import java.io.*;
/**
* 案例:使用字节流完成文件拷贝任务。
*/
public class StreamCopyDemo {
public static void main(String[] args) throws Exception {
// 分别创建文件的源对象和目标对象
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
// 创建输入和输出管道
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
// 读取/写出数据
byte[] buffer = new byte[1024]; // 设置每次读取的字节数
int len = -1; // 读取到的字节总数
while ((len = in.read(buffer)) != -1) {
// 写出数据
out.write(buffer, 0, len);
}
// 关闭输入/输出管道
in.close();
out.close();
}
}
与字节输入流在读取数据时使用的read()方法相对应的,字节输出流也提供了对应的写出数据的方法:write(),该方法也有一些重载方法:
out.write(int b);
// b 写入文件的字节
out.write(byte[] b);
// b 要写入文件的数据,类型为byte数组
out.write(byte[] b, int off, int len);
// 把字节数组中的从off索引开始的len个字节写到文件中
注意:字节流读写中的数据类型是字节数据类型(byte[])。
案例1,使用字节流完成文件拷贝任务。
import java.io.*;
/**
* 案例:使用字节流完成文件拷贝任务。
*/
public class StreamCopyDemo {
public static void main(String[] args) throws Exception {
// 分别创建文件的源对象和目标对象
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
// 创建输入和输出管道
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
// 读取/写出数据
byte[] buffer = new byte[1024]; // 设置每次读取的字节数
int len = -1; // 读取到的字节总数
while ((len = in.read(buffer)) != -1) {
// 写出数据
out.write(buffer, 0, len);
}
// 关闭输入/输出管道
in.close();
out.close();
}
}
字符流又分字符输入流(Reader)和字符输出流(Writer),分别对应文件读和写;需要注意的是:字符流读写中的数据类型是字符数据类型(char[]),区别于字节流中的字节类型(byte[])。
字符输入流,FileReader,字符输入流的使用案例代码如下:
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
/**
* 文件的字符输入流案例
*/
public class FileReaderDemo {
public static void main(String[] args) throws Exception {
// 创建资源对象
File src = new File("file_reader.txt");
// 创建文件字符输入流
Reader reader = new FileReader(src);
char[] buffer = new char[1024]; // 每次读取1024个字符
int len = -1; // 当前读取到的字符长度
while ((len = reader.read(buffer))!= -1) {
String line = new String(line, 0, len);
System.out.println(line);
}
// 关闭字符输入流
reader.close();
}
}
字符输入流在读取数据时使用的是read()方法,该方法还有另外的重载方法:
int read();
// 每次读取一个字符,直至文件末尾,返回-1为止int read(char[] buffer); // 每次都能读物多个字符,并把读取到的字符存储到buffer中
字符输出流,FileWriter,字符输出流的使用案例代码如下:
import java.io.*;
/**
* 文件的字符输出流案例
*/
public class FileWriterDemo {
public static void main(String[] args) throws Exception {
// 创建目标对象
File target = new File("file_writer.txt");
// 创建文件字符输出流
Writer writer = new FileWriter(target);
writer.write("dkgfkdsfowmsdfmowemfsdmfkemfkmfd");
writer.flush();
// 关闭字符输出流
writer.close();
}
}
字符输出流在读取数据时使用的是write()方法,该方法还有另外的重载方法:
void write(int c);
// 向文件中写出一个字符
void write(char[] buffer);
// 向文件中写出多个字符(char[] buffer)
void write(char[] buffer, int off, int len);
// 向文件中写出多个字符(char[] buffer),从off位置开始,长度为len
void write(String str);
// 向文字中写出一个字符串
案例2,使用字符流完成文件拷贝任务
import java.io.*;
/**
* 案例:使用字符流完成文件拷贝任务。
*/
public class FileCopyDemo {
public static void main(String[] args) throws Exception {
// 创建文件源对象和目标对象
File src = new File("file_reader.txt");
File target = new File("file_reader_copy.txt");
// 创建输入流和输出流
Reader reader = new FileReader(src);
Writer writer = new FileWriter(target);
// 文件读和写
char[] buffer = new char[1024];
int len = -1;
while((len = reader.read(buffer)) != -1) {
writer.write(buffer, 0, len);
}
// 关闭输入流和输出流
reader.close();
writer.close();
}
}
文件拷贝
案例3,使用流完成Java 代码动态编译、运行
import java.io.*;
/**
* 案例3,使用流完成Java 代码动态编译、运行
*/
public class EvalDemo {
public static void main(String[] args) {
String code = "System.out.println("Eval Java");";
try {
// 构建java代码
buildJavaCode(code);
// 编译Java 代码
compileJavaCode();
// 运行Java 代码
runJavaCode();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 构建java代码
*/
private static void buildJavaCode(String code) throws Exception {
// 拼接Java 主函数
StringBuilder builder = new StringBuilder(80);
builder.Append("public class Eval {");
builder.append("public static void main(String[] args) {");
builder.append(code);
builder.append("}");
builder.append("}");
// 保存拼接好的java代码到文件中
OutputStream out = new FileOutputStream("Eval.java");
out.write(builder.toString().getBytes("UTF-8"));
out.close();
}
/**
* 编译Java 代码
*/
private static void compileJavaCode() throws Exception {
// 调用javac 编译保存的java文件
Process javacProcess = Runtime.getRuntime().exec("javac Eval.java");
// 读取编译错误结果,并输出
InputStream error = javacProcess.getErrorStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = error.read(buffer)) != -1) {
String msg = new String(buffer, 0, len);
System.out.println("Eval 编译:" + msg);
}
// 关闭javac 编译进程
error.close();
}
/**
* 运行Java 代码
*/
private static void runJavaCode() throws Exception {
// 调用java 运行编译好的java字节码文件
Process javaProcess = Runtime.getRuntime().exec("java Eval");
// 读取java字节码文件的运行信息。并打印输出
InputStream info = javaProcess.getInputStream();
len = -1;
buffer = new byte[1024];
while ((len = info.read(buffer)) != -1) {
String msg = new String(buffer, 0, len);
System.out.println("Eval 运行: " + msg);
}
info.close();
// 删除java问价和class文件
new File("Eval.java").delete();
new File("Eval.class").delete();
}
}
在上述的字符输出流的使用案例中,使用了flush()方法,该方法有何作用呢?
因为计算机访问外部设备(磁盘文件)时,要比直接访问内存慢很多,如果每次调用write()方法都要直接把数据写出到磁盘文件中,CPU会花更多的时间,计算机执行性能会大大降低。
因此,我们可以准备一个内存缓冲区,程序每次调用write()方法时,会将数据先写到内存缓冲区中,暂存于缓冲区中;当内存缓冲区满后,系统才把缓冲区中暂存的数据一次性写出到磁盘文件中。这样就能减少直接操作本地文件系统的频率,使得系统性能得以提升。
flush()方法
flush(),刷新操作,输出流中都有flush方法。该方法的作用正是把缓冲区中暂存的数据一次性写出到磁盘文件中。
使用缓冲区的好处:
对于字节流,flush方法不是都有作用(部分字节流才有作用),对于字符流、缓冲流则都起作用。如果我们调用close方法关闭系统资源,那么,系统在关闭资源前,会先调用flush方法。
.
资源关闭分为手动关闭和自动关闭两种:
import java.io.*;
/**
* 资源关闭案例
*/
public class StreamCloseDemo {
public static void main(String[] args) {
// 资源手动关闭
closeManual();
// 资源自动关闭
closeAuto();
}
/**
* 资源手动关闭
*/
private static void closeManual() {
InputStream in = null;
OutputStream out = null;
try {
// 分别创建文件的源对象和目标对象
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
// 创建输入和输出管道
in = new FileInputStream(src);
out = new FileOutputStream(target);
// 读取/写出数据
byte[] buffer = new byte[1024]; // 设置每次读取的字节数
int len = -1; // 读取到的字节总数
while ((len = in.read(buffer)) != -1) {
// 写出数据
out.write(buffer, 0, len);
}
} catch (Exception e ) {
e.printStackTrace();
} finally {
// 关闭输入/输出管道
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 资源自动关闭
*/
private static void closeAuto() {
// 分别创建文件的源对象和目标对象
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
try (// 创建输入和输出管道
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
) {
// 读取/写出数据
byte[] buffer = new byte[1024]; // 设置每次读取的字节数
int len = -1; // 读取到的字节总数
while ((len = in.read(buffer)) != -1) {
// 写出数据
out.write(buffer, 0, len);
}
} catch (Exception e ) {
e.printStackTrace();
}
}
}
字节缓冲输入流,BufferedInputStream,案例代码如下:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* 字节缓冲输入流
*/
public class BufferedInputStreamDemo {
public static void main(String[] args) throws Exception {
// 字节输入流
InputStream in = new FileInputStream("stream.txt");
// 字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(in);
// 写出到文件的内容
String content = "BufferedOutputStream";
// 通过字节缓冲输入流读取数据
byte[] buffer = new byte[1024];
int len = -1;
while ((len = bis.read(buffer)) != -1) {
String line = new String(buffer, 0, len);
System.out.println(line);
}
in.close();
bis.close();
}
}
字节缓冲输出流,BufferedOutputStream,案例代码如下:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
* 字节缓冲输出流
*/
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws Exception {
// 字节输出流
OutputStream out = new FileOutputStream("stream.txt", true);
// 字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(out);
// 写出到文件的内容
String content = "BufferedOutputStream";
// 通过字节缓冲输出流写出数据
bos.write(content.getBytes());
out.close();
bos.close();
}
}
字符缓冲输入流,BufferedReader,案例代码如下:
import java.io.*;
/**
* 字符缓冲输入流
*/
public class BufferedReaderDemo {
public static void main(String[] args) throws Exception {
// 字符输入流
Reader reader = new FileReader("stream.txt");
// 字符缓冲输入流
BufferedReader br = new BufferedReader(reader);
// 读取文件内容
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
// 关闭流
reader.close();
br.close();
}
}
字符缓冲输出流,BufferedWriter,案例代码如下:
import java.io.*;
/**
* 字符缓冲输出流
*/
public class BufferedWriterDemo {
public static void main(String[] args) throws Exception {
// 字符输出流
Writer writer = new FileWriter("stream.txt");
// 字符缓冲输出流
BufferedWriter bw = new BufferedWriter(writer);
bw.write("这世界很美好");
bw.newLine();
bw.write("世界也很美好");
// 关闭流
writer.close();
bw.close();
}
}
字节流、缓冲流性能测试比较:
import java.io.*;
/**
* 字节流、缓冲流性能测试
*/
public class BufferedDemo {
public static void main(String[] args) {
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
try {
// 字节流性能测试
testSingleByteStream(src, target);
testSingleBufferedStream(src, target);
// 缓冲流性能测试
testMultiByteStream(src, target);
testMultiBufferedStream(src, target);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 字节流性能测试
* 每次读写都是一个字节
*
*/
private static void testSingleByteStream(File src, File target) throws Exception {
long begin = System.currentTimeMillis();
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
int len = -1;
while ((len = in.read()) != -1) {
out.write(len);
}
in.close();
out.close();
long end = System.currentTimeMillis();
System.out.println("SingleByteStream 耗费:" + (end - begin) + "ms");
}
/**
* 缓冲流性能测试
* 每次读写都是一个字节
*
*/
private static void testSingleBufferedStream(File src, File target) throws Exception {
long begin = System.currentTimeMillis();
// 创建文件流
InputStream srcStream = new FileInputStream(src);
OutputStream targetStream = new FileOutputStream(target);
// 穿甲缓冲流
InputStream in = new BufferedInputStream(srcStream);
OutputStream out = new BufferedOutputStream(targetStream);
int len = -1;
while ((len = in.read()) != -1) {
out.write(len);
}
// 关闭流
in.close();
out.close();
long end = System.currentTimeMillis();
System.out.println("SingleBufferedStream 耗费:" + (end - begin) + "ms");
}
/**
* 字节流性能测试
* 使用多字节读写
*
*/
private static void testMultiByteStream(File src, File target) throws Exception {
long begin = System.currentTimeMillis();
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
int len = -1;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
out.close();
long end = System.currentTimeMillis();
System.out.println("MultiByteStream 耗费:" + (end - begin) + "ms");
}
/**
* 缓冲流性能测试
* 使用多字节读写
*
*/
private static void testMultiBufferedStream(File src, File target) throws Exception {
long begin = System.currentTimeMillis();
// 创建文件流
InputStream srcStream = new FileInputStream(src);
OutputStream targetStream = new FileOutputStream(target);
// 穿甲缓冲流
InputStream in = new BufferedInputStream(srcStream);
OutputStream out = new BufferedOutputStream(targetStream);
int len = -1;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
// 关闭流
in.close();
out.close();
long end = System.currentTimeMillis();
System.out.println("MultiBufferedStream 耗费:" + (end - begin) + "ms");
}
}
上述测试运行结果如下:
SingleByteStream 耗费:3610ms
SingleBufferedStream 耗费:31ms
MultiByteStream 耗费:16ms
MultiBufferedStream 耗费:0ms
性能孰高孰低,测试结果已经很能说明问题了。
由于字节流和字符流同时存在,有时候会把二者结合起来使用,甚至在二者之间实现转换;为了实现这样的功能,Java IO中提供了字节流和字符流的适配器:
以下便是这个适配器—“转换流”的使用案例,案例通过文件的拷贝操作来体现,在读写的过程中,均使用了特定编码。案例代码实现如下:
import java.io.*;
/**
* 转换流案例
*/
public class StreamConvertDemo {
public static void main(String[] args) throws Exception {
// 创建文件对象
File src = new File("stream.txt");
File target = new File("stream_copy.txt");
// 创建文件流
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(target);
// 创建字节/字符转换流
Reader reader = new InputStreamReader(in, "UTF-8");
Writer writer = new OutputStreamWriter(out, "UTF-8");
// 操作字符流完成文件读写
char[] buffer = new char[1024];
int len = -1;
while ((len = reader.read(buffer)) != -1) {
writer.write(buffer, 0, len);
}
// 关闭流
in.close();
out.close();
reader.close();
writer.close();
}
}
为什么只有字节转字符流,却没有字符转字节流呢?原因也很简单:
字节流和字符流之间并不对等,无法实现转换,就比如C++程序可以运行C程序,但C程序却不能运行C++程序。
面向字节的数组流/内存流:ByteArrayInputStream和ByteArrayOutputStream;该“流”会把数据暂存到内存中,以便实时读写,读写时使用的字节类型(byte[]);
代码案例如下:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/**
* 面向字节的数组流/内存流
*/
public class ByteArrayDemo {
public static void main(String[] args) throws Exception {
String content = "dfjdslkfjdlsfjld";
// 字节数组输出流:程序 -> 内存
ByteArrayOutputStream bas = new ByteArrayOutputStream();
bas.write(content.getBytes());
// 缓存字节区
byte[] data = bas.toByteArray();
// 字节数组输入流:内存 -> 程序
ByteArrayInputStream bai = new ByteArrayInputStream(data);
byte[] buffer = new byte[1024];
int len = -1;
while ((len = bai.read(buffer)) != -1) {
String line = new String(buffer, 0, len);
System.out.println(line);
}
// 关闭流
bas.close();
bai.close();
}
}
面向字符的数组流/内存流,CharArrayReader和CharArrayWriter,该“流”会把数据暂存到内存中,以便实时读写,读写时使用的字符类型(char[]);
代码案例如下:
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
/**
* 面向字符的数组流/内存流
*/
public class CharArrayDemo {
public static void main(String[] args) throws Exception {
// 字符数组输出流
CharArrayWriter writer = new CharArrayWriter();
writer.write("这世界很美好");
char[] data = writer.toCharArray();
// 字符数组输入流
CharArrayReader reader = new CharArrayReader(data);
char[] buffer = new char[1024];
int len = -1;
while ((len = reader.read(buffer)) != -1) {
String line = new String(buffer, 0, len);
System.out.println(line);
}
// 关闭流
writer.close();
reader.close();
}
}
面向字符串的内存流,StringReader/StringWriter,把数据临时存储到字符串中,也同样是在内存中,但数据的类型是字符串;
案例代码如下:
import java.io.StringReader;
import java.io.StringWriter;
/**
* 面向字符串的内存流
*/
public class StringWriterReaderDemo {
public static void main(String[] args) throws Exception {
// 字符串输出流
StringWriter stringWriter = new StringWriter();
stringWriter.write("这世界很美好");
stringWriter.write("社会也很美好");
System.out.println(stringWriter.toString());
// 字符串输入流
StringReader stringReader = new StringReader(stringWriter.toString());
char[] buffer = new char[1024];
int len = -1;
while ((len = stringReader.read(buffer)) != -1) {
String line = new String(buffer, 0, len);
System.out.println(line);
}
// 关闭流
stringReader.close();
stringWriter.close();
}
}
合并流,SequenceInputStream:能够将2个或者以上的InputStream合并成一个单一的InputStream,进而进行合并操作;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.SequenceInputStream;
/**
* 合并流
*/
public class SequenceInputStreamDemo {
public static void main(String[] args) throws Exception {
// 创建输入队列流
SequenceInputStream seqIn = new SequenceInputStream(
new FileInputStream("stream1.txt"),
new FileInputStream("stream2.txt"),
new FileInputStream("stream3.txt"));
byte[] buffer = new byte[1024];
int len = -1;
while ((len = seqIn.read(buffer)) != -1) {
String line = new String(buffer, 0, len);
System.out.println(line);
}
seqIn.close();
}
}
字符编码的发展历程:
阶段1:计算机只认识数字0和1,计算机里的一切数据都是以数字来表示;因为英文符号有限,所以规定使用的字节的最高位是0,每一个字节都是以0~127之间的数字来表示,比如:A对应65,a对应97..这就是美国标准信息交换码-ASCII;
阶段2:随着计算机在全球的普及,很多国家和地区都把自己的字符引入了计算机中,比如汉字;但是ASCII中的一个字节能表示数字范围太小,不能包含所有的中文汉字,所以就规定使用两个字节来表示一个汉字;
所以决定,原有的ASCII字符的编码保持不变,仍然使用一个字节表示;为了区别一个中文字符与两个ASCII码字符:
阶段3:新的问题产生了,在中国是认识汉字的,支持GBK编码,但是如果把GBK编码的汉字传递给其他国家,该国家的编码表中没有收录该汉字的字符,故不能正常显示,很容易就出现了乱码。
为了解决各个国家因为本地化字符编码带来的影响,把全世界所有的符号统一进行编码-Unicode编码;此时某一个字符在全世界任何地方都是固定的,比如字符:'哥',在任何地方都是以十六进制的54E5来表示。Unicode的每个编码字符都占有2个字节大小。
常见的字符集:
编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。
互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。
存储字母,数字和汉字
存储字母和数字时无论是什么字符集都只占1个字节(因为和ASCII兼容),但是存储汉字:GBK家族占两个字节,UTF-8家族占3个字节。
存储中文时,GBK和UTF-8都是OK的。
import java.util.Arrays;
/**
* 字符编码
*/
public class EncodingDemo {
public static void main(String[] args) throws Exception {
String str = "老夫不正经";
// 以特定编码格式编码字符串
byte[] data = str.getBytes("UTF-8");
System.out.println(Arrays.toString(data));
// 解码字符串
str = new String(data, "ISO-8859-1");
System.out.println(str);
// 此时,字符串str是乱码:è夫ä¸æ£ç»
// 解决方案便是,使用ISO-8859-1来读取字节数据,然后使用UTF-8重新编码
data = str.getBytes("ISO-8859-1");
System.out.println(Arrays.toString(data));
str = new String(data, "UTF-8");
System.out.println(str);
}
}
完结,老夫虽不正经,但老夫一身的才华。