Java语言基础-IO流(输入输出流) 其他
Properties集合
Map
|--Hashtable
|--Properties
public class Properties extends Hashtable<Object,Object>
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
Properties集合:
特点:
1.该集合中的键和值都是字符串类型;
2.集合中的数据可以保存到流中或者从流中获取数据;
应用场景:通常该集合用于操作以键值对存在的配置文件。
package cn.itcase.io.p2.properties; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; import java.util.Set; public class PropertiesDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // propertiesDemo(); // propertiesDemo_2(); // propertiesDemo_3(); // propertiesDemo_4(); // myLoad(); test(); } // 对已有的配置文件中的信息进行修改 /* * 读取文件,并将这个文件中的键值数据存储到集合中; * 再通过集合对数据进行修改; * 再通过流将修改后的数据存储到文件中。 */ public static void test() throws IOException { // 读取这个文件 File file = new File("info.txt"); if (!file.exists()) { file.createNewFile(); } FileReader fr = new FileReader("info.txt"); // 如果放在这里,就新创建了文件覆盖掉原先的文件,文件为空 // FileWriter fw=new FileWriter(file); // 创建集合,存储配置信息 Properties prop = new Properties(); // 将流中的信息存储到集合中 prop.load(fr); prop.setProperty("wangwu", "16"); FileWriter fw = new FileWriter(file); prop.store(fw, ""); prop.list(System.out); fr.close(); } /** * 模拟load方法 * * @throws IOException */ public static void myLoad() throws IOException { Properties prop = new Properties(); BufferedReader bufr = new BufferedReader(new FileReader("info.txt")); String line = null; while ((line = bufr.readLine()) != null) { if (line.startsWith("#")) continue; String[] arr = line.split("="); // System.out.println(arr[0] + "::" + arr[1]); prop.setProperty(arr[0], arr[1]); } prop.list(System.out); bufr.close(); } public static void propertiesDemo_4() throws IOException { Properties prop = new Properties(); // 集合中的数据来自于一个文件 // 注意:必须要保证该文件中的数据时键值对 // 需要使用到读取流。 FileInputStream fis = new FileInputStream("info.txt"); // 使用load方法 prop.load(fis); prop.list(System.out); } /** * 将字符串键值持久化存储到文件中 * * @throws IOException */ public static void propertiesDemo_3() throws IOException { // 创建一个Properties集合 Properties prop = new Properties(); // 存储元素 prop.setProperty("zhangsan", "30"); prop.setProperty("lisi", "31"); prop.setProperty("wangwu", "36"); prop.setProperty("zhaoliu", "20"); // 将这些集合中的字符串键值信息持久化存储到文件中 // 需要关联输出流 FileOutputStream fos = new FileOutputStream("info.txt"); // 将集合中数据存储到文件中,使用store方法 prop.store(fos, "info"); } /** * 演示Properties集合与流对象相结合的功能 */ public static void propertiesDemo_2() { // 创建一个Properties集合 Properties prop = new Properties(); // 存储元素 prop.setProperty("zhangsan", "30"); prop.setProperty("lisi", "31"); prop.setProperty("wangwu", "36"); prop.setProperty("zhaoliu", "20"); prop.list(System.out);// 将键和值打印到控制台 // prop = System.getProperties();//获取系统信息 // System.out.println(prop); } /* * Properties集合的存和取 */ public static void propertiesDemo() { // 创建一个Properties集合 Properties prop = new Properties(); // 存储元素 prop.setProperty("zhangsan", "30"); prop.setProperty("lisi", "31"); prop.setProperty("wangwu", "36"); prop.setProperty("zhaoliu", "20"); // 修改元素 prop.setProperty("wangwu", "26"); // 取出所有元素 Set<String> names = prop.stringPropertyNames(); for (String name : names) { String value = prop.getProperty(name); System.out.println(name + ":" + value); } } }
Properties集合应用示例:
package cn.itcase.io.p2.properties; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; /* * 定义功能:获取一个应用程序运行的次数,如果超过5次, * 给出使用次数已到请注册的提示,并不再运行程序 * * 思路: * 1.需要计数器 * 每次程序启动计数器需要计数一次,并且是在原有的次数上进行计数; * 2.计数器就是一个变量 * 程序启动时,进行计数,计数器必须存在于内存中并进行运算; * 程序结束时,计数器会消失。那么再次启动该程序,计数器就重新被初始化。 * 需要多次启动同一个应用程序,使用的是同一个计数器。 * 这就需要计数器的生命周期编程,从内存存储到硬盘文件中。 * 3.如何使用计数器? * 首先,程序启动时,应先读取这个用于记录计数器信息的配置文件, * 获取上一次计数次数,并进行试用次数的判断。 * 其次,对该次数进行自增,并将自增后的次数重新存储到配置文件中。 * 4.文件中信息的存储和体现 * 使用键值对。 * 可以使用有映射关系的map类集合,所以map+io=Properties */ public class PropertiesTest { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { getAppCount(); } public static void getAppCount() throws IOException { // 将所需的配置文件封装成File对象 File confile = new File("count.properties"); if (!confile.exists()) { confile.createNewFile(); } FileInputStream fis = new FileInputStream(confile); Properties prop = new Properties(); prop.load(fis); // 从集合中通过键获取次数 String value = prop.getProperty("time"); // 定义计数器,记录获取到的次数 int count = 0; if (value != null) { count = Integer.parseInt(value); if (count >= 5) { // System.out.println("使用次数已到,请注册!"); // return; throw new RuntimeException("使用次数已到,请注册!"); } } count++; // 将改变后的次数重新存储到集合中 prop.setProperty("time", count + ""); FileOutputStream fos = new FileOutputStream(confile); prop.store(fos, ""); fos.close(); fis.close(); } }
文件清单列表
package cn.itcase.io.p3.test; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.List; /* * 获取指定目录下,指定扩展名的文件(包含子目录中的) * 这些文件的绝对路径写入到一个文本文件中 * * 简单说,就是一个指定扩展名的文件列表 * * 思路: * 1.必须继承深度遍历; * 2.要在遍历的过程中进行过滤,将符合条件的内容都存储到容器中; * 3.对容器中的内容进行遍历,并将内容写入到文件中。 */ public class Test { /** * @param args */ public static void main(String[] args) { //创建File对象 File dir=new File("e:\\PalInn"); //实现过滤器 FilenameFilter filter=new FilenameFilter(){ @Override public boolean accept(File dir, String name) { return name.endsWith(".exe"); } }; //创建暂存文件列表的list List<File> list=new ArrayList<File>(); //遍历文件 getFiles (dir,filter,list); //创建要存储信息的目标文件 File destFile=new File(dir,"exelist.txt"); //将list中存储的信息写入到目标文件中 write2File(list, destFile); } /** * 对指定目录中的内容进行深度遍历,并按照指定过滤器,进行过滤 * * @param dir 要遍历的目录 * @param filter 过滤器 * @param list 暂存信息的容器 */ public static void getFiles(File dir, FilenameFilter filter, List<File> list) { File[] files = dir.listFiles(); for (File file : files) { if (file.isDirectory()) { // 递归 getFiles(file, filter, list); } else { // 对遍历到的文件进行过滤,将符合条件的file对象存储到list集合中 if (filter.accept(file, file.getName())) { list.add(file); } } } } public static void write2File(List<File> list, File destFile) { BufferedWriter bufw = null; try { bufw = new BufferedWriter(new FileWriter(destFile)); for(File file:list){ bufw.write(file.getAbsolutePath()); bufw.newLine(); bufw.flush(); } } catch (IOException e) { throw new RuntimeException("写入失败!"); } finally { if (bufw != null) try { bufw.close(); } catch (IOException e) { throw new RuntimeException("关闭失败!"); } } } }
打印流-PrintStream
public class PrintStream extends FilterOutputStream implementsAppendable, CloseablePrintStream
为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。
package cn.itcase.io.p4.print.demo; import java.io.IOException; import java.io.PrintStream; public class PrintDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * PrintStream * 1.提供了打印的方法,可以对多种数据类型值进行打印,并保持数据的表示形式; * 2.它不抛出异常(IOException); * * 构造函数接收三种类型的值: * 1.字符串路径; * 2.File对象; * 3.字节输出流。 */ PrintStream out = new PrintStream("print.txt"); // int by=read(); // write(by); // out.write(97);//a-97,二进制为0110-0001 out.write(610);// b-98,只写最低8位,610二进制为10 0110-0010 // out.print(97);//97,保持表示形式。将97先变成字节串保持原样,再打印到目的地 out.close(); } }
public class PrintWriter extends Writer
向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。
package cn.itcase.io.p4.print.demo; import java.io.BufferedReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; public class PrintWriterDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * PrintWrite 字符打印流 * 构造函数参数: * 1.字符串路径; * 2.File对象; * 3.字节输出流; * 4.字符输出流。 */ BufferedReader bufr = new BufferedReader(new InputStreamReader( System.in)); // PrintWriter out = new PrintWriter(System.out, true);// true,自动刷新 PrintWriter out = new PrintWriter(new FileWriter("out.txt"), true);// true,自动刷新 String line = null; while ((line = bufr.readLine()) != null) { if ("over".equals(line)) break; out.println(line.toUpperCase()); // out.flush(); } out.close(); bufr.close(); } }
序列流-SequenceInputStream
可以对多个流进行合并。(只负责源)
public class SequenceInputStream extends InputStreamSequenceInputStream
表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
枚举和迭代:
package cn.itcase.io.p4.sequence.demo; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.SequenceInputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; public class SequenceInputStreamDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * 需求:将1.txt、2.txt、3.txt文件中的数据合并到一个文件中 */ // Vector<FileInputStream> v=new Vector<FileInputStream>(); // // v.add(new FileInputStream("1.txt")); // v.add(new FileInputStream("2.txt")); // v.add(new FileInputStream("3.txt")); ArrayList<FileInputStream> al = new ArrayList<FileInputStream>(); for (int x = 1; x <= 3; x++) { al.add(new FileInputStream(x + ".txt")); } Enumeration<FileInputStream> en = Collections.enumeration(al); /* * final Iterator<FileInputStream> it=al.iterator(); * * Enumeration<FileInputStream> en=new Enumeration<FileInputStream>(){ * * @Override * public boolean hasMoreElements() { * return it.hasNext(); * } * * @Override * public FileInputStream nextElement() { * return it.next(); * } * * }; */ 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); } fos.close(); sis.close(); } }
文件切割示例:
package cn.itcast.io.p1.splitefile; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; /** * 文件切割器 * @author chenchong * */ public class SplitFileDemo { private static final int SIZE = 1024 * 1024; /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { File file = new File("c:\\0.bmp"); splitFile(file); } public static void splitFile(File file) throws IOException { // 用读取流关联源文件 FileInputStream fis = new FileInputStream(file); // 定义一个1M的缓冲区 byte[] buf = new byte[SIZE]; // 创建目的 FileOutputStream fos = null; int len = 0; int count = 1; /* * 切割文件时,必须记录被切割文件的名称,以及切割出来的碎片文件的个数,以方便与合并。 * 这个信息为了进行简单的描述,使用键值对的方式,用到了properties对象 */ Properties prop = new Properties(); File dir = new File("c:\\partfiles"); if (!dir.exists()) dir.mkdirs(); while ((len = fis.read(buf)) != -1) { fos = new FileOutputStream(new File(dir, (count++) + ".part")); fos.write(buf, 0, len); fos.close(); } // 将被切割文件的信息保存到prop集合中 prop.setProperty("partcount", count + ""); prop.setProperty("filename", file.getName()); fos = new FileOutputStream(new File(dir, count + ".properties")); // 将prop中的数据存储到文件中 prop.store(fos, "save file info"); fis.close(); } }
文件合并示例:
package cn.itcast.io.p1.splitefile; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.SequenceInputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Properties; /** * 文件合并器 * @author chenchong * */ public class MergeFile { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { File dir = new File("c:\\partfiles"); mergeFile(dir); } public static void mergeFile(File dir) throws IOException { /* * 获取指定目录下的配置文件对象 */ File[] files = dir.listFiles(new SuffixFilter(".properties")); if (files.length != 1)// 没有properties,则抛出异常 throw new RuntimeException(dir + ",该目录下没有properties扩展名的文件或者不唯一"); // 记录配置文件对象 File confile = files[0]; // 获取该文件中的信息=============================== Properties prop = new Properties(); FileInputStream fis = new FileInputStream(confile); prop.load(fis); String filename = prop.getProperty("filename"); int count = Integer.parseInt(prop.getProperty("partcount")); // 获取该目录下的所有碎片文件============================ File[] partFiles = dir.listFiles(new SuffixFilter(".part")); if (partFiles.length != (count - 1)) { throw new RuntimeException("碎片文件不符合要求,个数不对。应该是" + count + "个"); } // 将碎片文件和流对象关联并存储到集合中 ArrayList<FileInputStream> al = new ArrayList<FileInputStream>(); for (int x = 0; x < partFiles.length; x++) { al.add(new FileInputStream(partFiles[x])); } // 将多个流合并成一个序列流 Enumeration<FileInputStream> en = Collections.enumeration(al); SequenceInputStream sis = new SequenceInputStream(en); FileOutputStream fos = new FileOutputStream(new File(dir, filename)); byte[] buf = new byte[1024]; int len = 0; while ((len = sis.read(buf)) != -1) { fos.write(buf, 0, len); } fos.close(); sis.close(); } }
过滤器:
package cn.itcast.io.p1.splitefile; import java.io.File; import java.io.FilenameFilter; /** * 过滤器 * @author chenchong * */ public class SuffixFilter implements FilenameFilter { private String suffix; public SuffixFilter(String suffix) { super(); this.suffix = suffix; } @Override public boolean accept(File dir, String name) { return name.endsWith(suffix); } }
操作对象
ObjectInputStream、ObjectOutputStream。
被操作的对象需要实现Serializable(标记接口)。
public interface Serializable
类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
public final void writeObject(Object obj) throws IOException
将指定的对象写入 ObjectOutputStream。对象的类、类的签名,以及类及其所有超类型的非瞬态和非静态字段的值都将被写入。
package cn.itcast.io.p1.objectstream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import cn.itcast.io.p2.bean.Person; public class objectStreamDemo { /** * @param args * @throws IOException * @throws ClassNotFoundException */ public static void main(String[] args) throws IOException, ClassNotFoundException { // writeObj(); readObj(); } public static void readObj() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "obj.object")); // 对象的反序列化 Person p = (Person) ois.readObject(); System.out.println(p.getName() + ":" + p.getAge()); ois.close(); } public static void writeObj() throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( "obj.object")); // 对象的序列化。被序列化的对象必须实现Serializalbe接口 oos.writeObject(new Person("小强", 30)); oos.close(); } }
package cn.itcast.io.p2.bean; import java.io.Serializable; /* * Serializable用于给被序列化的类加入序列号 * 用于判断类和对象是否是同一版本 */ public class Person implements Serializable/* 标记接口 */{ /** * transient,非静态数据,又不想被序列化,可以使用该关键字修饰。 */ private static final long serialVersionUID = 9527L; private transient String name;// transient修饰的成员,不写入硬盘 private int age; public Person(String name, int age) { super(); this.age = age; this.name = name; } public Person() { super(); } 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; } }
RandomAccessFile
随机访问文件,自身具备读写的方法;
通过skipBytes(int x),seek(int x),来达到随机访问的目的。
public class RandomAccessFile extends Objectimplements DataOutput, DataInput, Closeable
此类的实例支持对随机访问文件的读取和写入。
package cn.itcast.io.p3.randomfiles; import java.io.IOException; import java.io.RandomAccessFile; public class RandomAccessFileDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { /* * RandomAccessFile * 不是IO体系中的子类; * 特点: * 1.该对象既能读,又能写; * 2.该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素; * 3.可以通过getFilePointer获取指针的位置,通过seek方法设置指针的位置; * 4.其实,该对象就是将字节输入流和输出流进行了封装; * 5.该对象的源或者目的只能是文件,通过构造函数就可以看出; */ // writeFile(); // readFile(); randomWrite(); } public static void randomWrite() throws IOException { RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "rw"); // 往指定位置写入数据 raf.seek(3 * 8); raf.write("赵六".getBytes()); raf.writeInt(102); raf.close(); } public static void readFile() throws IOException { RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r"); // 通过seek设置指针的位置 raf.seek(1 * 8);// 实现随机的读取,只要指定指针的位置即可 byte[] buf = new byte[4]; raf.read(buf); String name = new String(buf); int age = raf.readInt(); System.out.println("name:" + name); System.out.println("age:" + age); System.out.println("pos:" + raf.getFilePointer()); raf.close(); } // 使用RandomAccessFile对象写入一些人员信息 public static void writeFile() throws IOException { /* * 如果文件不存在,则创建;如果文件存在,则不创建。 */ RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "rw"); raf.write("张三".getBytes()); // raf.write(609);//只保留低8位 // raf.writeInt(609);//先写高位 raf.writeInt(97); // raf.write("小强".getBytes()); // raf.writeInt(98); raf.close(); } }
管道流
PipedInputStream、PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用
package cn.itcast.io.p4.piped; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class PipedStream { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { PipedInputStream input=new PipedInputStream(); PipedOutputStream output=new PipedOutputStream(); input.connect(output); new Thread(new Input(input)).start(); new Thread(new Output(output)).start(); } } class Input implements Runnable { private PipedInputStream in; Input(PipedInputStream in) { this.in = in; } public void run() { try { Thread.sleep(5000); byte[] buf = new byte[1024]; int len = in.read(buf); String s = new String(buf, 0, len); System.out.println("s=" + s); in.close(); } catch (Exception e) { } } } class Output implements Runnable { private PipedOutputStream out; Output(PipedOutputStream out) { this.out = out; } public void run() { try { out.write("Hey,管道来了!".getBytes()); } catch (Exception e) { } } }
操作基本数据类型
DataInputStream、DataOutputStream
package cn.itcast.io.p5.datastream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class DataStreamDemo { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // writeData(); readData(); } public static void readData() throws IOException { DataInputStream dis = new DataInputStream(new FileInputStream( "data.txt")); String str = dis.readUTF(); System.out.println(str); dis.close(); } public static void writeData() throws IOException { DataOutputStream dos = new DataOutputStream(new FileOutputStream( "data.txt")); dos.writeUTF("你好"); dos.close(); } }
操作字节数组
ByteArrayInputStream、ByteArrayOutputStream
public class ByteArrayOutputStream extends OutputStream
此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
public class ByteArrayInputStream extends InputStreamByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
关闭 ByteArrayOutputStream、ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 (没有调用底层资源)
package cn.itcast.io.p6.bytestream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public class ByteArrayStreamDemo { /** * @param args */ public static void main(String[] args) { ByteArrayInputStream bis = new ByteArrayInputStream( "abcdefg".getBytes()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int ch = 0; while ((ch = bis.read()) != -1) { bos.write(ch); } System.out.println(bos.toString()); // bos.close();//无效,不需要关闭 } }
简单的编码解码
package cn.itcast.io.p7.encode; import java.io.UnsupportedEncodingException; public class EncodeDemo { /** * @param args * @throws UnsupportedEncodingException */ public static void main(String[] args) throws UnsupportedEncodingException { /* * 字符串——>字节数组,编码 * 字节数组——>字符串,解码 * 你好(GBK):-60 -29 -70 -61 * 你好(UTF-8):-28 -67 -96 -27 -91 -67 * * 如果编码错误,解码不出来 * 如果编码正确,解码有可能解出 */ String str = "你好";// -60 -29 -70 -61 byte[] buf = str.getBytes("gbk"); String s1 = new String(buf, "iso8859-1");//查表错误 System.out.println("s1=" + s1);//解码错误 byte[] buf2 = s1.getBytes("iso8859-1");//获取源字节 String s2=new String(buf2,"gbk");//重新解码 System.out.println("s2="+s2); // encodeDemo(str); } /** * @param str * @throws UnsupportedEncodingException */ public static void encodeDemo(String str) throws UnsupportedEncodingException { // 编码 byte[] buf = str.getBytes("utf-8"); // printBytes(buf); // 解码 String s1 = new String(buf); System.out.println("s1=" + s1); } public static void printBytes(byte[] buf) { for (byte b : buf) { System.out.print(b); } } }
练习-按字节截取字符串
package cn.itcast.io.p7.encode; import java.io.IOException; /* * 在java中,字符串"abcd",与字符串"ab你好"的长度是一样的,都是四个字符。 * 但相应的字节数不同,一个汉字占两个字节。 * 定义一个方法,按照最大的字节数来取子串。 * 如:对于"ab你好",如果去三个字节,那么子串就是ab与“你”字的半个, * 那么半个就要舍弃。如果取四个字节就是"ab你",去五个字节还是"ab你" */ public class Test { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { String str = "ab你好cd谢谢"; // String str = "ab琲琲cd琲琲";// 琲,-84 105 // int len = str.getBytes("gbk").length; // for (int x = 0; x < len; x++) { // System.out.println("截取" + (x + 1) + "个字节结果是:" // + cutStringByBytes(str, x + 1)); // } int len = str.getBytes("utf-8").length; for (int x = 0; x < len; x++) { System.out.println("截取" + (x + 1) + "个字节结果是:" + cutStringByU8Bytes(str, x + 1)); } } public static String cutStringByU8Bytes(String str, int len) throws IOException { byte[] buf = str.getBytes("utf-8"); int count = 0; for (int x = len - 1; x >= 0; x--) { if (buf[x] < 0) count++; else break; } if (count % 3 == 0)// utf-8码,三个字节组成 return new String(buf, 0, len, "utf-8"); else if (count % 3 == 1) return new String(buf, 0, len - 1, "utf-8"); else return new String(buf, 0, len - 2, "utf-8"); } public static String cutStringByBytes(String str, int len) throws IOException { byte[] buf = str.getBytes("gbk"); int count = 0; for (int x = len - 1; x >= 0; x--) { if (buf[x] < 0) count++; else break; } if (count % 2 == 0) return new String(buf, 0, len, "gbk"); else return new String(buf, 0, len - 1, "gbk"); } }