一、IO概述
IO是InputOutput的缩写,IO流即输入输出流。
1、IO流:
1) 用来处理设备之间的数据传输。
2) Java 对数据的操作是通过IO流操作的。
3) Java用于操作流的对象都在IO包中。
4) 流只能操作数据。
5) 流按操作数据分两种:字节流、字符流;流按流向分为:输入流、输出流。
Note:字符流融合了编码表,用于处理文字。字节流用于处理图片、文字,通用的是字节流。程序从输入流中读取数据,向输出流中写入数据。在数据类型上,read()方法在作提升,write()方法在做强转,以保证原数据的不变化。
2、IO 流常用类:
字节流的抽象基类:InputStream、OutputStream
字符流的抽象基类:Reader、Writer
字符流:FileWriter、FileReader (字符流缓冲区:BufferedWriter、BufferedReader)
字节流:FileOutputStream、FileInputStream (字节流缓冲区:BufferedOutputStream、BufferedInputStream)
Note:由这四类派生出来的子类名称都是以其父类名作为子类名的后缀。
eg:InputStream 的子类 FileInputStream Reader 的子类 FileReader
二、字符流
字符流是字节流根据指定编码表编码而得到的,所以字符流是在字节流之后出现的。
字符流有以下特点:
1、字符流中的对象融合了编码表。默认的编码,即当前系统的编码。
2、字符流只用于处理文字数据,而字节流可以处理媒体数据。
Writer:写入字符流的抽象类。
子类必须实现的方法仅有 writer()、flush()、close(),多数子类将重写方法,以提供更高的效率和其他功能。IO流是用于操作数据的,而数据的最常见体现形式是文件。查看API,找到一个专门用于操作文件的Writer子类:FileWriter。
1、字符流的读写
a、字符流写入
步骤:
1) 创建文件。创建一个 FileWriter 对象,该对象一初始化就必须要明确被操作的文件。而且该文件会被创建到指定的目录下。如果该目录下已有同名文件,已有文件将被覆盖。明确数据要存放的目的地(文件)。
eg:FileWriter fw=new FileWriter(“demo.txt”);
2) 调用 writer 方法,将字符串写入(内存)流中。
eg:fw.writer(“abcfgggg”);
3) 刷新流对象中的缓冲区数据。将数据刷新到目的地(文件) 。
eg:fw .flush();
4) 关闭流资源(必须有的步骤)。但关闭之前会刷新一次内部缓冲区中的数据,将数据刷新到目的地(文件)。
eg:fw.close();
flush() 与 close() 的区别:
flush() 刷新后,流一直存在,可以继续写入数据。
close() 刷新后会将流关闭,不能再继续写入数据。关闭资源需要单独做 try 处理。
Note:
1) 其实java自身不能写入数据,而是调用系统内部方式完成数据的书写,使用系统资源后,一定要关闭资源。
2) 文件的数据的续写是通过构造函数 FileWriter(Strings,boolean append),在创建对象时,传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。(windows系统中的文件内换行用\r\n两个转义字符表示,在linux系统中只用\n表示换行)。
3) 由于在创建对象时,需要指定创建文件位置,如果指定的位置不存在,就会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。
示例如下:
import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class FileWriterDemo { public static void main(String[] args) { // FileWriter(File file) 创建一个file关联的字符流对象,file对象随之创建 Writer file = null; try { file = new FileWriter("fileWriter.txt"); // 调用write方法,将字符串写入字符流中 file.write("fileDemo"); // 刷新字符流中的缓冲,将数据刷新到目的地文件中 file.flush(); // flush刷新后流资源还可以使用,close关闭之后流资源不能访问 } catch (IOException e) { throw new RuntimeException("文件写入失败"); } finally { // 关闭之前判空操作提高效率 if (file != null) { try { file.close(); } catch (IOException e) { throw new RuntimeException("文件关闭失败"); } } } } }b、字符流读取
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class FileReaderDemo { public static void main(String[] args) { readerMethod_1(); readerMethod_2(); } public static void readerMethod_2() { FileReader fr = null; try { fr = new FileReader("FileWriterDemo.java"); // 定义一个字符数组用于存储读到的字符 // read(char[] ch)返货的是读到的字符个数 char[] buf = new char[1024]; int num = 0; // int read(char[] buf) 返回本次读取到的字符个数 while ((num = fr.read(buf)) != -1) { System.out.print(new String(buf, 0, num)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } } public static void readerMethod_1() { FileReader fr = null; try { // 创建一个文件读取流对象,和指定文件名相关联 // 要保证该文件是存在的,否则会报FileNoFoundException fr = new FileReader("FileWriterDemo.java"); int ch = 0; // read()一次读取一个字符 while ((ch = fr.read()) != -1) { System.out.print((char) ch); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }当我们读取文件的时候,上述示例中的第二种方法是先创建了一个字符数组用于存储读取到的字符,然后利用read(buf)方法一次读取多个字符并返回字符个数,这样一来就比之前的read()方法,每次只读取一个字符来得要快,其中的字符数组buf就可以称为字符缓冲区。而Java中也提供了字符缓冲区对象。
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyTextByBuf { public static void main(String[] args) { // 定义文件读取流、输出流缓冲区 BufferedReader br = null; BufferedWriter bw = null; try { // 将缓冲区关联文件 br = new BufferedReader(new FileReader("buf.txt")); bw = new BufferedWriter(new FileWriter("copyofbuf.txt")); // buf记录缓冲区读取到的字符数据 String buf = null; while ((buf = br.readLine()) != null) { bw.write(buf);// 向缓冲区中写入数据 bw.newLine();// 换行 bw.flush();// 刷新缓冲区中的数据到目的文件中去 } } catch (IOException e) { throw new RuntimeException("文件操作失败"); } finally {// 最后关闭资源 if (bw != null) { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } }LineNumberReader
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; public class LineNumberReaderDemo { public static void main(String[] args) { // 定义字符读取流 FileReader fr = null; LineNumberReader lnb = null; try { fr = new FileReader("FileWriterDemo.java"); // 让LineNumberReader关联一个存在的字符读取流 lnb = new LineNumberReader(fr); String line = null; // 设置读取初始行号为100 lnb.setLineNumber(100); while ((line = lnb.readLine()) != null) { System.out.println(lnb.getLineNumber() + " " + line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally {// 关闭资源 if (lnb != null) { try { lnb.close(); } catch (IOException e) { e.printStackTrace(); } } if (fr != null) { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }三、字节流
示例如下:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class OutputStreamDemo { public static void main(String[] args) { // fileOutputStream(); // fileInputStream_1(); // fileInputStream_2(); fileInputStream_3(); } // 逐个字节读取 public static void fileInputStream_1() { FileInputStream fis = null; try { fis = new FileInputStream("fos.txt"); int ch = 0; while ((ch = fis.read()) != -1) { System.out.print((char) ch); } } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } } // 借助缓冲数组buf,一次读取多个字节的形式完成文件读取操作 public static void fileInputStream_2() { FileInputStream fis = null; try { fis = new FileInputStream("fos.txt"); byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { System.out.println(new String(buf, 0, len)); } } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } } // 借助特有方法avaliable()返回的文件大小建立一个字节数组,在完成读取操作 public static void fileInputStream_3() { FileInputStream fis = null; try { fis = new FileInputStream("fos.txt"); // 获取待读取文件的大小 int numOfChar = fis.available(); // 创建一个刚刚好的缓冲区 byte[] buf = new byte[numOfChar]; int len = 0; while ((len = fis.read(buf)) != -1) { System.out.println(new String(buf, 0, len)); } } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } } // 字节写入操作演示 public static void fileOutputStream() { FileOutputStream fos = null; try { fos = new FileOutputStream("fos.txt"); fos.write("abcdef".getBytes()); } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } } }2、字节流缓冲区
/* 自定义字节流读取缓冲区 思路: 1、定义一个固定长度的数组 2、定义一个指针和计数器用于读取数组长度,和计数数组元素是否取完为0 3、每次将字节数据存入元素要先将数组中的元素取完 */ import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; class MyBufferedInputStream { private InputStream in; private byte[] by = new byte[1024]; private int count = 0, pos = 0; MyBufferedInputStream(InputStream in) { this.in = in; } // 自定义读方法,一次读一个字节 public int myRead() throws IOException { // 通过in对象读取硬盘上数据,并存储by中。 // 存储在数组中的数据被读取完,再通过in对象从硬盘上读取数据 if (count == 0) { count = in.read(by); if (count < 0)// 文件数据全部被读取出来了 return -1; pos = 0;// 初始化指针 byte b = by[pos]; count--;// 每被读一个字节,表示数组中的字节数少一个 pos++;// 指针加1 return b & 255;// 返回的byte类型提升为int类型,字节数增加,且高24位被补1,原字节数据改变。 // 通过与上255,主动将byte类型提升为int类型,将高24位补0,原字节数据不变。 // 而在输出字节流写入数据时,只写该int类型数据的最低8位。 } else if (count > 0)// 如果数组中的数据没被读取完,则继续读取 { byte b = by[pos]; count--; pos++; return b & 0xff; } return -1; } // 自定义关闭资源方法 public void close() throws IOException { in.close(); } } // 测试自定义输入字节流缓冲区 public class MyBufferedCopyMp3 { public static void main(String[] args) { // 利用字节流的缓冲区进行复制 copy(); } // 使用字节流的缓冲区进行复制 public static void copy() { BufferedOutputStream bout = null; MyBufferedInputStream bin = null; try { // 关联复制文件输入流对象到缓冲区 bin = new MyBufferedInputStream(new FileInputStream( "E:\\BaiduMusic\\Songs\\My Love - Westlife.mp3")); // 指定文件粘贴位置的输出流对象到缓冲区 bout = new BufferedOutputStream(new FileOutputStream( "My Love - Westlife.mp3")); int by = 0; while ((by = bin.myRead()) != -1) { bout.write(by);// 将缓冲区中的数据写入指定文件中 } } catch (IOException e) { throw new RuntimeException("MP3复制失败"); } finally { try { if (bin != null) bin.close();// 关闭输入字节流 } catch (IOException e) { throw new RuntimeException("读取字节流关闭失败"); } try { if (bout != null) bout.close();// 关闭输出字节流 } catch (IOException e) { throw new RuntimeException("写入字节流关闭失败"); } } } }3、转换流
示例如下:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; public class ReaderInAndWriterOut { public static void main(String[] args) throws IOException { InputStreamMethod(); changeMethod(); } public static void changeMethod() throws IOException { // 改变标准输入输出流 System.setIn(new FileInputStream("FileWriterDemo.java")); System.setOut(new PrintStream("char.txt")); // 获取键盘录入对象 InputStream in = System.in; // 将字节流转换成字符流对象使用转换流InputStreamReader InputStreamReader isr = new InputStreamReader(in); // 为提高效率,将字符串进行缓冲区技术的操作使用BufferedReader BufferedReader br = new BufferedReader(isr); // 简化书写如下: BufferedReader bufferReader = new BufferedReader(new InputStreamReader( System.in)); BufferedWriter bufferWriter = new BufferedWriter( new OutputStreamWriter(System.out)); // 获取控制台输出 对象 OutputStream out = System.out; OutputStreamWriter osw = new OutputStreamWriter(out); BufferedWriter bw = new BufferedWriter(osw); String line = null; while ((line = br.readLine()) != null) { if ("over".equals(line)) { break; } // System.out.println(line.toUpperCase()); bw.write(line.toUpperCase()); bw.newLine(); bw.flush(); } br.close(); } // 自定义键盘录入方法 public static void InputStreamMethod() throws IOException { InputStream in = System.in; StringBuilder sb = new StringBuilder(); int ch = 0; while (true) { ch = in.read(); if (ch == '\r') { continue; } if (ch == '\n') { String s = sb.toString(); if (s.equals("over")) { break; } System.out.println(s.toUpperCase()); // 将缓冲区清空 sb.delete(0, sb.length()); } else { sb.append((char) ch); } } } }5、流操作规律
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyPic { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream( "C:\\Users\\caven\\Desktop\\HeiMa\\IMG_ME.jpg"); fos = new FileOutputStream("ME1.jpg"); byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { fos.write(buf, 0, len); } } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } if (fos != null) { try { fos.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } } }四、File类
import java.io.File; import java.io.IOException; /* * File类:将文件或者文件夹封装成对象 * File常见方法演示: */ public class FileDetials { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub // fileConstructMethod(); // method_1(); // method_2(); // method_3(); method_4(); } public static void method_4() throws IOException { File f = new File("abc\\file.txt"); System.out.println("createNewFile::" + f.createNewFile()); System.out.println("path::" + f.getPath()); System.out.println("AbsolutePath::" + f.getAbsolutePath()); System.out.println("Parent::" + f.getParent()); System.out.println("Modified::" + f.lastModified()); System.out.println("length::" + f.length()); } public static void method_3() throws IOException { File f = new File("file.txt"); // 判断文件对象是否是文件或者文件目录之前,必须先判断文件对象是否存在exists() // f.createNewFile(); // f.delete(); // f.mkdir(); System.out.println("isAbsolute::" + f.isAbsolute()); System.out.println("isHidden::" + f.isHidden()); System.out.println("file::" + f.isFile()); System.out.println("dir::" + f.isDirectory()); } public static void method_2() throws IOException { File f = new File("FileWriterDemo.java"); // System.out.println("canExecute::" + f.canExecute()); System.out.println("exsits::" + f.exists()); } public static void method_1() throws IOException { File f = new File("file.txt"); // 虚拟机退出时删除文件 f.deleteOnExit(); boolean flag1 = f.delete(); System.out.println("delete::" + flag1); boolean flag = f.createNewFile(); System.out.println("createNewFile::" + flag); File dir = new File("abc\\edf"); System.out.println("mkdir::" + dir.mkdirs()); } // 创建File对象 public static void fileConstructMethod() { // 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 File f = new File("file.txt"); // 创建指定父目录下的文件对象 // File.separator跨平台的文件分割符 File fileUnderParent = new File("D:" + File.separator + "JDoc", "file.txt"); System.out.println(f); System.out.println(fileUnderParent); } }五、Properties类
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Set; public class PropertiesDemo { public static void main(String[] args) throws IOException { // setAndGet(); // info2Map(); loadDemo(); } // 加载设置文件中的信息并修改打印在控制台 public static void loadDemo() throws IOException { Properties prop = new Properties(); FileInputStream fis = new FileInputStream("info.txt"); prop.load(fis); // System.out.println(prop); FileOutputStream fos = new FileOutputStream("info.txt"); prop.store(fos, "ok"); prop.setProperty("lisi", "38"); prop.list(System.out); } /* * 需求:将info.txt中的键值对数据存入到集合中 1、用一个流对象与文件info.txt关联 2、读取一行数据,用“=”进行切割 * 3、等号左边为键,右边为值,存入到Properties中 */ public static void info2Map() throws IOException { BufferedReader br = new BufferedReader(new FileReader("info.txt")); String line = null; Properties prop = new Properties(); while ((line = br.readLine()) != null) { String[] datas = line.split("="); // prop.put(datas[0],datas[1]); prop.setProperty(datas[0], datas[1]); // System.out.println(line); } br.close(); System.out.println(prop); } // 设置和获取元素 public static void setAndGet() { Properties prop = new Properties(); prop.put("zhangsan", "12"); prop.put("nihao", "33"); System.out.println(prop); String age = prop.getProperty("nihao"); System.out.println("age::" + age); Set<String> names = prop.stringPropertyNames(); System.out.println(names); for (String name : names) { System.out.println(name + ".." + prop.getProperty(name)); } } }五、其他IO类
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; /* * 打印流: */ public class OtherClass { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); PrintWriter pr = new PrintWriter(new BufferedWriter(new FileWriter( "a.txt")), true); String line = null; while ((line = br.readLine()) != null) { if ("over".equals(line)) { break; } pr.println(line); // pr.flush(); } pr.close(); br.close(); } }3、序列流
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.SequenceInputStream; import java.util.Enumeration; import java.util.Vector; /* * 文件合并 * SequenceInputStream * 1、SequenceInputStream(Enumeration en) * 2、SequenceInputStream(FileInputStream file1,FileInputStream file2) * */ public class SequenceDemo { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub Vector<FileInputStream> v = new Vector<FileInputStream>(); v.add(new FileInputStream("1.txt")); v.add(new FileInputStream("2.txt")); v.add(new FileInputStream("3.txt")); Enumeration<FileInputStream> en = v.elements(); SequenceInputStream sis = new SequenceInputStream(en); FileOutputStream fos = new FileOutputStream("4.txt"); byte[] buf = new byte[1024]; int len = 0; while ((len = sis.read(buf)) != -1) { fos.write(buf, 0, len); } sis.close(); fos.close(); } }4、管道流
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; //创建Peason类,实现Serializable接口 class Person implements Serializable { private static final long serialVersionUID = -4461523780114351798L; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); } } public class ObjectStreamDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { writeObject(); readObject(); } // 读取指定文件中的对象,也称反序列化 public static void readObject() throws FileNotFoundException, IOException, ClassNotFoundException { File file = new File("object.txt"); if (!file.exists()) { return; } ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); Person p = (Person) ois.readObject(); System.out.println(p); ois.close(); } // 将指定对象序列化到指定文件中 public static void writeObject() throws IOException, FileNotFoundException { File file = new File("object.txt"); if (!file.exists()) { file.createNewFile(); } ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( file)); oos.writeObject(new Person("zhangsan", 313)); oos.close(); } }
6、字节数组的流:
ByteArrayInputStream和ByteArrayOutputStream
这个对象并没有调用底层资源,所以不用关闭流资源,即使关闭后,仍可调用。 内部包含缓冲区,相当于以内存作为流操作源和目的,不会产生任何IO异常。对象中封装了数组,其实就是用流的思想操作数组。
构造函数:
ByteArrayInputStream:在构造函数的时候,需要接受数据源,而且数据源是一个字节数据。
ByteArrayOutputStream:在构造函数的时候,不用定义数据目的,因为该对象中已经在内部封装了可变长度的字节数组,这就是数据的目的地。
特有方法:
ByteArrayOutputStream中:
writeTo(OutputStream out); //将此 byte数组输出流的全部内容写入到指定的输出流参数中,这与使用out.write(buf, 0, count)调用该输出流的 write方法效果一样。因为这个方法用到了字节输出流,需要抛IO异常,也是字节数组流中唯一需要抛异常的方法。
int size(); //当前缓冲区的大小
String toString(); //使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
示例如下:
import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; public class ByteArrayStreamDemo { @SuppressWarnings({ "unused", "resource" }) public static void main(String[] args) throws IOException { // TODO Auto-generated method stub // 定义一个字节读取流---数据源 ByteArrayInputStream bais = new ByteArrayInputStream( "ABCDEF".getBytes()); BufferedInputStream bufIn = new BufferedInputStream( new FileInputStream("FileWriterDemo.java")); // 字节写入流---目的 ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len = 0; while ((len = bufIn.read()) != -1) { baos.write(len); } System.out.println(baos.size()); System.out.println(baos.toString()); } }7、字符编码
UTF-8编码格式:
一个字节:0开头
两个字节:字节一 ---> 110 位数:10 ~ 6
字节二 ---> 10 位数:5 ~ 0
三个字节:字节一 ---> 110 位数:15 ~ 12
字节二 ---> 10 位数:11 ~ 6
字节三 ---> 10 位数:5 ~ 0
转换流的编码应用:
可以将字符以指定编码格式存储。可以对文本数据指定编码格式来解读。指定编码表的动作由构造函数完成。
编码和解码
1) 编码:字符串变成字节数组
默认字符集: String ---> byte[] :srt.getBytes()
指定字符集:String ---> byte[] :srt.getBytes(charsetName)
2) 解码:字节数组变成字符串
默认字符集: byte[] ---> String :new String(byte[])
指定字符集: byte[] ---> String :newString(byte[],charsetName)
对于编码和解码的字符集转换注意事项
1) 如果编码失败,解码就没意义了。
2) 如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。
3) 如果用的是GBK编码,UTF-8解码,此时通过再次编码后解码的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。
如使用了错误的解码表:
4) 特别注意:对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,所以在文本文件中,如果单独写“联通”或者和满足UTF-8编码格式的字符一起保存时,记事本就会用UTF-8来进行解码动作,这样显示的就会是乱码。
以上所述仅代表个人看法,如有出入请谅解。