06 Java SE IO
By Kevin Song
- 06-01 IO流概述
- 06-02 字节流和字符流
- 06-02-01 字符流
- 06-02-02 字节流
- 06-02-03 转换流
- 06-02-04 IO流的操作规律
- 06-03 File类
- 06-03-01 递归
- 06-04 Properties集合
- 06-05 其他IO类
- 06-05-01 打印流
- 06-05-02 序列流
- 06-05-03 ObjectStream
- 06-05-04 RandomAccessFile类
- 06-05-05 管道流
- 06-05-06 DataStream
- 06-05-07 操作数组的流
- 06-05-08 编码表
06-01 IO流概述
概述
- IO流用来处理设备之间的数据传输
- Java对数据的操作是通过流的方式
- Java用于操作流的对象都在IO包中
IO流对于内存设备而言
- 输入:把外设中的数据读取到内存中
- 输出:把内存的数写入到外设中
IO流分类
- 流按操作数据分为两种
- 字节流
- 字符流
- 流按流向分为
- 输入流
- 输出流
06-02 字节流和字符流汇总
06-02-01 字符流
IO体系
- 字节流的顶层父类
- InputStream
- FileInputStream
- BufferedInputStream
- OutputStream
- FileOutputStream
- BufferedOutputStream
- InputStream
- 字符流的顶层父类
- Reader
- FileReader
- BufferedReader
- InputStreamReader 转换流
- Writer
- FileWirter
- BufferedWirter
- OutputStreamWriter 转换流
- Reader
字符流特点:只能操作文字
字符流由来:字节流读取文字字节数据后,不直接操作,而是先查指定的编码表。获取对应的文字,再对这个文字进行操作
字符流 = 字节流 + 编码表
FileWirter类
定义:字符输出流子类,其对象可以向文件中写入字符数据
注意:
- 该类没有空构造方法因为往文件中写入文字数据必须在创建对象时明确该文件
- 如果文件不存在,自动创建
- 如果文件已存在,自动覆盖
方法
- wirte(“Hello World!”) 写入数据到临时存储缓冲区
- flush() 刷新,把数据从临时存储缓冲区存储到目的地
- close() 关闭流,关闭资源,关闭前会调用flush刷新缓冲中的数据到目的地
public class FileWriter {
public static void main(String[] args) {
//创建一个可以往文件中写入字符数据的字符输出流对象
//创建对象时必须初始化
FileWriter fw = new FileWriter("JAVA.txt", true);
//把数据写入临时存储缓冲区
fw.wirte("Hello World!");
//刷新,将数据直接写入目的地
fw.flush();
//关闭流,关闭资源,关闭前会调用flush刷新缓冲中的数据到目的地
fw.close();
}
}
细节
- 换行:创建变量private static final String LINE_SEPARATOR = null; 进行换行
- 续写:在构造方法里写上true,可以在原有的文件上续写
- new FileWirter(“JAVA.txt”,true)
IO异常处理
public class FileWriter {
public static void main(String[] args) {
FileWriter fw = null
try {
new FileWriter("JAVA.txt", );
fw.wirte("Hello World!");
} catch(IOException e) {
System.out.println(e.toString());
} finally {
if(fw != null)
try {
fw.close();
} catch(IOException e) {
throw new RuntimeException("关闭失败");
}
}
}
}
FileReader类
定义:字符输出流子类,其对象可以读取一个文本文件,并且打印到控制台
注意:
- 该类没有空构造方法因为读取文件的时候该文件必须存在
- 其实就是用一个读取流关联一个已存在的文件
- 读取时一个read只能读取一个字符
方法
- 读取方式
- 读取方式一 read() 读取字符,一次只能读一个
- 读取方式二 read(char []) 读取字符,存入数组
- close() 关闭流,关闭资源,关闭前会调用flush刷新缓冲中的数据到目的地
读取方式一
public class FileWriter {
public static void main(String[] args) {
//创建读取字符数据的流对象
//一定要确定文件是存在的
//用一个读取流关联一个已存在的文件
FileReader fr = new FileReader("JAVA.txt");
//用Reader中的read方法读取字符
int ch = fr.read();
System.out.println(ch);
//重复读取
while((ch=fr.read())!= -1) {
System.out.println((char)ch);
}
fr.close;
}
}
读取方式二
public class FileWriter {
public static void main(String[] args) {
FileReader fr = new FileReader("JAVA.txt");
//创建字符数组
char[] buf = new char[3];
//把读取的数据存入数组
int num = fr.read(buf);
System.out.println(new String(buf));
//重复读取
while((len=fr.read(buf)) != -1) {
System.out.println(new String(buf,0,len ));
}
}
}
读写练习
复制一个文件到C盘
思路
- 读取源数据
- 将读取的数据写入目的地
- 用字符流操作文本数据
复制方式一
public class FileTest {
public static void main(String[] args) throws IOExcepion {
//读取文本文件
FileReader fr = new FileReader("JAVA.txt");
//存储文本文件
FileWriter fw = new FileWirter("JAVA_COPY.txt");
//重复读取
int ch = 0;
while((ch=fr.read()) != -1) {
fw.wirte(ch);
}
fr.close();
fw.close();
}
}
复制方式二
public class FileTest {
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args) throws IOExcepion {
FileReader fr = null;
FileWirter fw = null;
try {
fr = new FileReader("JAVA.txt");
fw = new FileWirter(JAVA_COPY.txt);
//创建一个临时容器
char[] buf = new char[BUFFER_SIZE];
//定义一个变量记录读取到的字符数
int len = 0;
while((len=fr.read(buf)) != -1)
fw.wirte(buf, 0, len);
} catch(Excepion e) {
throw new RuntimeException("读写失败");
} finally {
if(fw != null)
try {
fw.close;
} catch(IOException e) {
e.printStackTrace();
}
if(fw != null)
try {
fr.close;
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
缓冲区
提高了IO流操作效率
- BufferedReader
- BufferedWirter
BufferWirter类
构造方法:传入一个要被缓冲的流对象
常用方法
- wirte:写入
- newLine():换行
- flush:刷新
- close:关闭,缓冲区关闭之后,被缓冲的流对象也被自动关闭
public class BufferWirterDemo {
public static void main(String[] args) {
//创建写入流对象
FileWriter fw = new FileWriter("buf.txt");
//创建一个字符写入流的缓冲区对象
//缓冲区对象和要被缓冲的流对象关联
BufferedWriter bufw = new BufferedWriter(fw);
bufw.write("abc");
bufw.newLine();//换行
bufw.write("def");
bufw.flush();
bufw.close();
}
}
BufferReader类
构造方法:传入一个要被缓冲的流对象
常用方法
- read();读取一个字符
- readLine():读取一整行
- 原理:使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记,返回标记前的缓存数据
public class BufferReaderDemo {
public static void main(String[] args) {
//创建读取流对象
FileReader fr = new FileReader("buf.txt");
//创建一个字符读取流的缓冲区对象
//缓冲区对象和要被缓冲的流对象关联
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line = bufr.readLine()) != null) {
System.out.println(line);
}
}
}
缓冲区复制文件
方式一
public class CopyDemo {
public static void main(String[] args) {
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("buf_copy.txt");
BufferedWirter bufw = new BufferedWirter(fw);
inc ch = 0;
while((ch=bufr.read())!=-1) {
bufw.write(ch);
}
bufw.close();
bufr.close();
}
}
方式二
一行一行复制
public class CopyDemo {
public static void main(String[] args) {
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("buf_copy.txt");
BufferedWirter bufw = new BufferedWirter(fw);
String line = null;
while((line=bufr.readLine())!= -1) {
bufw.write(line);
}
bufw.close();
bufr.close();
}
}
自定义BufferReader
public class MyBufferReader {
private FileReader r;
//缓冲区全局数组
private char[] buf = new charp[1024];
//操作数组中元素指针
private int pos = 0;
//计数器:记录缓冲区中的数据个数
MyBufferedReader(FileReader r) {
this.r = r;
}
public int myRead() throws IOException {
If(count == 0) {
count = r.read(buf);
pos = 0;
}
if(count < 0)
return -1;
char ch = buf[pos++];
count--;
return ch;
/*
if(count==0) {
count = r.read(buf);
if(count < 0) {
return -1;
}
pos = 0;//每次获取数据到缓冲区后,角标归零
char ch = buf[pos];
pos++;
count--;
return ch;
} else if(count > 0) {
char ch = buf[pos];
pos++;
count--;
return ch;
}
*/
}
public String myReadLine() {
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch = myRead())!=-1) {
if(ch == '\r') {
continue;
} else if(ch == '\n') {
return sb.toString();
} else {
//从缓冲区中读到的字符存储到缓存行数据的缓冲区中
sb.append((char)ch);
}
}
return null;
}
public void myClose() {
r.close();
}
}
LineNumberReader类
作用:可以读取行数
方法
- setLineNumber():设置起始行数
- readLine():整行读取
- close():关闭
public class LineNumberReaderDemo {
public static void main(String[] args) {
FileReader fr = new FileReader();
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
//设置起始行数
lnr.setLineNumber(1);
while((line=lnr.readLine())!=null) {
System.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close(0;)
}
}
装饰设计模式
定义:对一组对象的功能进行增强的设计模式
特点:装饰类和被装饰类都必须所属同一个接口或者父类
装饰和继承异同
- 相同点:都能实现对象功能的增强
- 不同点
- 装饰比继承灵活
装饰灵活性的体现
传统继承扩展
Writer
- TextWriter:用于操作文本
- BufferedTextWriter
- MediaWriter:用于操作媒体
- BufferedMediaWriter
- WebWriter:用于操作网页
- BufferedWebWriter
- ServerWriter:用于操作服务器
- BufferedServerWriter
装饰设计扩展
Writer
- TextWriter:用于操作文本
- MediaWriter:用于操作媒体
- WebWriter:用于操作网页
- ServerWriter:用于操作服务器
- BufferedWriter:提高效率
public class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
EnhancedPerson p1 = new EnhancedPerson(p);
p1.eat();
EnhancedPerson2 p2 = new EnhancedPerson2();
p2.eat();
}
}
class Person {
void eat() {
System.out.println("Steak");
}
}
//装饰
class EnhancedPerson {
private Person p;
EnhancedPerson(Person p) {
this.p = p;
}
public void eat() {
System.out.println("Appetizer");
p.eat();
System.out.println("Dessert");
}
}
//继承
class EnhancedPerson2 extends Person{
public void eat() {
System.out.println("Appetizer");
super.eat();
System.out.println("Dessert");
}
}
06-02-02 字节流
- 字节流的顶层父类
- InputStream
- FileInputStream
- OutputStream
- FileOutputStream
- InputStream
常用方法
- FileInputStream
- read();
- available(); 获取字节长度
- FileOutputStream
- write()
字节流操作文件基本演示
public class ByteStreamDemo {
public static void main(String[] args) {
demo_read();
demo_write();
}
public static void demo_read() {
//创建字节读取流对象,和指定文件关联
FileInputStream fis = new FileInputStream("bytedemo.txt");
//一次读取一个字节
int ch = fis.read();
System.out.println((char)ch);
//全部读取完毕
int ch = 0;
while((ch=fis.read())!=-1) {
System.out.println((char)ch);
}
//用数组来读取
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=0) {
System.out.println(new String(buf,0,len));
}
//用available()方法读
byte[] buf = new byte[fis.available()];
fis.read(buf);
System.out.println(new String(buf));
}
public static void demo_write() {
//创建字节输出流对象,用于操作文件
FileOutputStream fos = new FileOutputStream("bytedemo.txt");
//写数据,直接写入到目的地中
fos.write("abc".getBytes());
}
}
字节流读取MP3练习
public class CopyDemo {
public static void main(String[] args) {
copy_1();
copy_2();
copy_3();
}
//1024字节复制一次
public static void copy_1() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
byte[] buf = new byte[1024];
int len = 0;
while((buf=fis.read())!=0) {
System.out.println(new String(buf,0,len));
}
}
//用Buffered的复制
public static void copy_2() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
int ch = 0;
while((ch=bufis.read())!=-1) {
bufos.write(ch);
bufos.flush();
}
bufos.close();
bufis.close();
}
public static void copy_3() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
byte[] buf = new byte[fis.available()];
fis.read(buf);
fos.write(buf);
fos.close();
fis.close();
}
}
IO流键盘输入
键盘输入演示
public class ReadKey {
public static void main(String[] args) throws IOException {
readKey1();
readKey2();
}
public static void readKey1() throws IOException {
//创建输入流对象
InputStream in = System.in;
//读取输入流对象的内容
int ch = in.read();
System.out.println(ch);
}
public static void readKey2() throws IOException {
inputStream in = System.in;
int ch = 0;
while((ch=in.read()!=-1)) {
System.out.println(ch);
}
}
}
键盘录入转换成大写
获取用户键盘录入的数据,并且转换成大写显示在控制台上,exit退出录入
思路
- 因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串
- 需要一个容器StringBuilder来存储字符串
- 回车之前把录入的数据变成字符串判断
public class ReadKey {
public static void main(String[] args) throws IOException {
readKey();
}
获取用户键盘录入的数据,并且转换成大写显示在控制台上,exit退出录入
public static void readKey() throws IOException {
//创建容器
StringBuilder sb = new StringBuilder();
//获取键盘读取流
inputStream in = System.in;
//定义变量记录读取到的字节,循环获取
int ch = 0;
while((ch=in.read())!=-1) {
if (ch=='\r')
continue;
if (ch=='\n') {
String temp = sb.toString();
if("exit".equals(temp))
break;
System.out.println(temp.toUpperCase());
sb.delete(0,sb.length());
} else {
sb.append((char)ch);
}
}
}
}
06-02-03 转换流
- InputStreamReader
- 字节流 –> 字符流
- 字节 解码成 字符
- OutputStreamWriter
- 字符流 –> 字节流
- 字符 编码成 字节
作用
- InputStreamReader:把字节流解码成字符流,使其可以使用诸如readLine()之类的方法
- OutputStreamWriter:把字符流编码成字节流,进行输出
转换关系
这两句代码功能相同
FileWriter:相当于用了本机默认码表的转换流。是一个便捷类
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");
FileReader fr = new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"))
FileWriter fw = new FileWriter("a.txt");
转换流实现键盘录入转换成大写
需求:键盘录入数据显示在控制台上
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
/*
字节流获取
InputStream in = System.in;
字节流解码成字符流
InputStreamReader isr new InputStreamReader(in);
字符流装饰
BufferedReader bufr = new BufferedReader(isr);
*/
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
/*
字节流
OutputStream out = System.out;
字符流编码成字节流
OutputStreamWriter osw = new OutputStreamWriter(out);
字符流装饰
BufferedWriter bufw = new BufferedWriter(osw);
*/
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null) {
if("exit".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
需求:键盘录入数据写入一个文件中
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"));
需求:文本文件内容显示在控制台上
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out);
需求:文本文件内容写入另一个文件中(复制)
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt"));
转换关系
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");
FileReader fr = new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"))
FileWriter fw = new FileWriter("a.txt");
这两句代码功能相同
FileWriter:相当于用了本机默认码表的转换流。是一个便捷类
如果要用别的编码,必须使用转换流。
用UTF-8写
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"), "UTF-8");
用UTF-8读
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "UTF-8");
转换流使用场合
- 源目对应的设备是字节流但是操作的确是文本数据,可以使用转换作为桥梁
- 操作文本需要用制定编码表时,必须使用转换流
06-02-04 IO流的操作规律
四个明确
- 明确源和目的(汇)
- 源
- InputStream 字节流
- Reader 字符流
- 目的
- OutputStream 字节流
- Writer 字符流
- 源
- 明确数据是否是纯文本数据
- 源
- 是纯文本 Reader
- 不是纯文本 InputStream
- 目的
- 是纯文本 Writer
- 不是纯文本 OutputStream
- 源
- 明确据具体设备
- 源
- 硬盘:File
- 键盘:System.in
- 内存:数组
- 网络:Socket流
- 目的
- 硬盘:File
- 控制台:System.out
- 内存:数组
- 网络:Socket流
- 源
- 是否需要额外功能
- 是否需要高效(Buffer)
- 是否需要转换
需求体现
需求1:复制一个文本文件
- 明确源目的
- 源 InputStream Reader
- 目的 OutputStream Writer
- 是否纯文本:是
- 源:Reader
- 目的:Writer
- 明确设备
- 源:硬盘File
- FileReader fr = new FileReader(“a.txt”);
- 目的:硬盘File
- FileWriter fw = new FileWriter(“b.txt”);
- 源:硬盘File
- 明确是否需要额外功能:需要高效
- 源:
- BufferedReader bufr = new BufferedReader(fr);
- 目的:
- BufferedWriter bufw = new BufferedWriter(fw);
- 源:
需求2 键盘录入数据,存入文件
- 明确源目的
- 源 InputStream Reader
- 目的 OutputStream Writer
- 是否纯文本:是
- 源:Reader
- 目的:Writer
- 明确设备
- 源:键盘 System.in
- InputStream in = System.in;
- 目的:硬盘 File
- FileWriter fw = new FileWriter(“b.txt”);
- 源:键盘 System.in
- 明确是否需要额外功能:
- 需要转换
- 源:
- InputStreamReader isr = new InputStreamReader(System.in);
- 目的:
- FileWriter fw = new FileWriter(“b.txt”);
- 源:
- 需要高效
- 源:
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- 目的:
- BufferedWriter bufw = new BufferedWriter(new FileWriter(“b.txt”));
- 源:
- 需要转换
需求3 读取文本文件显示在控制台上
- 明确源目的
- 源 InputStream Reader
- 目的 OutputStream Writer
- 是否纯文本:是
- 源:Reader
- 目的:Writer
- 明确设备
- 源:硬盘 File
- FileReader fr = new FileReader(“a.txt”);
- 目的:控制台 System.out
- OutputStream out = System.out;
- 源:硬盘 File
- 明确是否需要额外功能:
- 需要转换
- 源:
- FileReader fr = new FileReader(“a.txt”);
- 目的:
- OutputStreamWriter osw = new OutputStreamWriter(System.out);
- 源:
- 需要高效
- 源:
- BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
- 目的:
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- 源:
- 需要转换
需求4 键盘录入数据显示在控制台上
- 明确源目的
- 源 InputStream Reader
- 目的 OutputStream Writer
- 是否纯文本:是
- 源:Reader
- 目的:Writer
- 明确设备
- 源:控制台 System.in
- InputStream in = System.in;
- 目的:控制台 System.out
- OutputStream out = System.out;
- 源:控制台 System.in
- 明确是否需要额外功能:中文一个字两个字节,所以需要转换成字符串操作
- 需要转换
- 源:
- InputStreamReader isr = new InputStreamReader(System.in);
- 目的:
- OutputStreamWriter osw = new OutputStreamWriter(System.out);
- 源:
- 需要高效
- 源:
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- 目的:
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- 源:
- 需要转换
06-03 File类
File类特点
- 用来将文件或者文件夹封装成对象
- 方便对文件和文件夹的属性信息进行操作
- File对象可以作为参数传递给流的构造方法
构造方法
- 传入一个字符串文件路径
File file1 = new File("c:\\a.txt");
- 传入一个字符串文件夹路径,一个文件名
File file2 = new File("c:\\", "a.txt");
- 传入一个文件对象,一个文件名
File f = new File("c:\\");
File file3 = new File(f, "a.txt");
分隔符的应用
File file4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt");
public class FileDemo {
public static void main(String[] args) {
constructiorDemo();
}
public static void constructiorDemo() {
//可以将一个已存在的,或者不存在的文件或者目录封装成file对象
File file1 = new File("c:\\a.txt");
File file2 = new File("c:\\", "a.txt");
File f = new File("c:\\");
File file3 = new File(f, "a.txt");
File file4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt");
}
}
常用方法
- 获取
- 获取文件名称:getName()
- 获取文件路径
- 获取相对路径:getAbsolutePath()
- 获取绝对路径:getPath()
- 获取文件大小:getLength()
- 获取文件修改时间:lastModified()
public static void getDemo() {
File file = new File("a.txt");
String name = file.getName(); a.txt
String absPath = file.getAbsolutePath(); C:\abc\a.txt //绝对路径
String path = file.getPath(); a.txt
long len = file.length(); 123
long time = file.lastModified(); 1236102144203
}
- 创建与删除
- 创建删除文件
- boolean createNewFile()
- 如果文件不存在,则创建
- 如果文件存在,则不创建
- boolean delete()
- boolean createNewFile()
- 创建删除文件夹
- 创建单级目录
- mkdir()
- 创建多级目录
- mkdirs()
- 删除文件夹
- boolean delete()
- 创建单级目录
- 创建删除文件
public static void createAndDeleteDemo() {
File file = new File("file.txt");
boolean a = file.createNewFile();
System.out.println(a); true
boolean b = file.delete();
System.out.println(b); true
}
- 判断
- 判断是否存在 isDemo()
- 判断是否是文件 isFile()
- 判断是否是文件夹 isDirectory()
public static void isDemo() {
File file = new File("aa.txt");
boolean b = file.exists();
System.out.println(b);true
}
- 重命名
- renameTo();
public static void isDemo() {
File file1 = new File("aa.txt");
File file2 = new File("bb.txt");
file1.renameTo(file2);
}
- 获取系统根目录
- listRoots();
public static void listRootsDemo() {
File[] file1 = File.listRoots();
for(File file : files) {
System.out.println(file);
}
}
- 获取容量
- getFreeSpace() 获取空闲空间
- getTotalSpace() 获取总空间
- getUsableSpace() 获取已用空间
public static void getSpaceDemo() {
File file = new File("d:\\");
file.getFreeSpace();
file.getTotalSpace();
file.getUsableSpace();
}
- 获取目录
- String list()
- file必须是一个目录
- 否则发生NullPointerException
- 访问系统级目录也会发生空指针异常
- 如果目录没有内容,会返回一个数组,长度为0
- 返回的是文件和文件夹名字
- File listFiles()
- 返回的是文件对象数组
- String list()
public static void listDemo() {
File file = new File("c:\\");
String[] names = file.list();
for(String name : names) {
System.out.println(name);
}
}
- 过滤器
只要Java文件
public static void listDemo2() {
File dir = new File("c:\\");
String[] names = dir.list(new FilterByJava());
for(String name : names) {
System.out.println(name);
}
}
public class FilterByJava implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
}
自定义过滤器
public static void listDemo2() {
File dir = new File("c:\\");
String[] names = dir.list(new FilterByJava());
for(String name : names) {
System.out.println(name);
}
}
public class SurffixFilter implements FilenameFilter {
private String suffix;
public SurffixFilter(String suffix) {
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
}
深度遍历
列出所有文件和目录
public class FileTest {
public static void main(String[] aregs) {
File dir = new File("e:\\demodir");
listAll(dir);
}
public static void listAll(File dir) {
System.out.println(getSpace(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for(int x = 0; x<files.length; x++) {
if(files[x].idDirectory()) {
listAll(files[x]);
} else {
System.out.println(getSpace(level)+files[x].getName());
}
}
}
private static String getSpace(int level) {
StringBuilder sb = new StringBuilder;
for(int x = 0; x<level; x++) {
sb.append(" ");
}
return sb.toString();
}
}
删除所有文件和目录
原理:从里往外删
public class FileDeleteTest {
public static void main(String[] aregs) {
File dir = new File("e:\\demodir");
removeDir(dir);
}
public static void removeDir(File dir) {
File[] files = dir.listFiles();
for(File file : files) {
if(file.isDirectory()) {
removeDir(file);
} else {
file.delete();
}
}
dir.delete();
}
}
06-03-01 递归
定义:方法自身调用自身
注意:
- 递归一定要明确条件,否则容易栈溢出
转成二进制
public static void toBinary(int num) {
if(num>0) {
System.out.println(num%2);
toBinary(num/2);
}
0
1
1
}
public static void toBinary(int num) {
if(num>0) {
toBinary(num/2);
System.out.println(num%2);
}
1
1
0
}
求和
public static int getSum(int num) {
if(num == 1)
return 1;
return num+getSum(num-1);
}
求和栈内存图解
int getNum(2 - 1) {
if(1 == 1)
return; 1
return 1 + getSum(1 - 1);
}
int getNum(3 - 1) {
if(2 == 1)
return;
return 2 + getSum(2 - 1); 1+2
}
int getNum(4 - 1) {
if(3 == 1)
return;
return 3 + getSum(3 - 1); 3+3
}
int getNum(5 - 1) {
if(4 == 1)
return;
return 4 + getSum(4 - 1); 4+6
}
int getNum(5) {
if(5 == 1)
return;
return 5 + getSum(5 - 1); 5+10
}
06-04 Properties集合
基本功能
- Map
- Hashtable
- Properties
- HashMap
- TreeMap
- Hashtable
Properties集合特点:
- 集合中的Key和Value都是字符串类型
- 集合中的数据可以保存到流中,获取从流中获取数据
Properties集合作用:通常该集合用于操作该键值对形式存在的配置文件
- 一 存取功能
- setProperty
- getProperty
public static void propertiesDemo() {
//创建一个Properties集合
Properties prop = new Properties();
//储存元素
prop setProperty("Kevin", 24);
prop setProperty("Tony", 21);
prop setProperty("Brian", 19);
prop setProperty("Peter", 29);
//取出元素
Set<String> names = prop.stringPropertyName();
for(String name : names) {
String value = prop.getProperty(name);
System.out.println(name+":"+value);
}
}
- 二 list方法列出
public static void propertiesDemo() {
//创建一个Properties集合
Properties prop = new Properties();
//储存元素
prop setProperty("Kevin", 24);
prop setProperty("Tony", 21);
prop setProperty("Brian", 19);
prop setProperty("Peter", 29);
//列出元素
prop.list(System.out);
}
- 三 store方法存储
public static void propertiesDemo() {
//创建一个Properties集合
Properties prop = new Properties();
//储存元素
prop setProperty("Kevin", 24);
prop setProperty("Tony", 21);
prop setProperty("Brian", 19);
prop setProperty("Peter", 29);
//储存到文件中
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos,"name+age");
fos.close();
}
- 四 读取文件,输出到控制台
public static void propertiesDemo() {
//创建一个集合
Properties prop = new Properties();
//文件和输入流绑定
FileInputStream fis = new FileInputStream("info2.txt");
//把文件加载进集合
prop.load(fis);
//输出集合到控制台
prop.list(System.out);
}
//模拟load方法
public static void myLoad() {
Properties prop = new Properties();
BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
String line = null;
while((line=bufr.readLine())!=null) {
if(line.startsWith("#")) {
continue;
} else {
String[] arr = line.split("=");
prop.setProperty(arr[0], arr[1]);
}
}
bufr.close();
}
- 五 对已有的配置文件进行修改
思路
- 读取文件
- 把文件中的Key和Value数据存入集合
- 通过集合修改Key和Value数据
- 把修改后的数据存入文件
public static void propertiesDemo() {
//文件封装成对象
File file = new File("info.txt");
//判断文件是否存在
if(!file.exists()) {
file.createNewFile();
}
//文件读取
FileReader fr = new FileReader(file);
//创建集合存储信息
Properties prop = new Properties();
//将流中信息存储到集合中
prop.load(fr);
//修改数据
prop.setProperties("Kevin", "24");
//文件和输出流绑定
FileWriter fw = new FileWriter(file);
//存储修改后的数据
prop.store(fw,"");
fw.close();
fr.close();
}
练习
练习一:获取一个应用程序的运行次数,如果超过5次,给出使用次数已到请注册的提示。并结束运行
思路
- 计数器:每次程序启动都计数一次
- 计数器不能随着程序的关闭而重置,所以储存在硬盘里
- 计数器原理
- 程序启动时,先读取
public class PropertiesTest {
public static void main (String[] args) {
}
public static void getAppCount() {
File confile = new File("count.properties");
if(!confile.exists()) {
confile.createNewFile();
}
FileInputStream fis = new FileInputStream(confile);
Properties prop = new Properties();
prop.load(fis);
//从集合中通过Key获取次数
String value = prop.getProperty("time");
//定义计数器,记录获取到的次数
int count = 0;
if(value!=null) {
count = Integer.parseInt(value);
if(count >= 5) {
System.out.println("使用次数已到");
}
}
count++;
//改变后的次数重新存储到集合中
prop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(confile);
fos.close();
fis.close();
}
}
练习二:建立一个制定扩展名的文件的列表
思路:
- 需要进行深度遍历
- 要在遍历的过程中进行过滤,将符合条件的内容存储到容器中
- 对容器中的内容进行遍历,并将绝对路径写入文件中
public class Test {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
File dir = new File("e:\\java0331");
FilenameFilter filter = new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
};
List<File> list = new ArrayList<File>();
getFiles(dir,filter,list);
File destFile = new File(dir,"javalist.txt");
write2File(list,destFile);
}
/**
* 对指定目录中的内容进行深度遍历,并按照指定过滤器,进行过滤,
* 将过滤后的内容存储到指定容器List中。
* @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(dir, file.getName())){
list.add(file);
}
}
}
}
public static void write2File(List<File> list,File destFile)throws IOException{
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("关闭失败");
}
}
}
}
06-05 其他IO类
06-05-01 打印流
- PrintStream 字节
- PrintWriter 字符
装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintStream
特点:
- 提供了print方法,可以对多种数据类型值进行打印,并保持数据的表示形式
- 不抛出IOException
构造方法:能接收三种类型的值
- 字符串路径 (String fileName)
- File对象 (File file)
- 字节输出流 (OutputStream out)
方法
- write(97)
- 输出a:只写最低8位
- print(97)
- 输出97:把97变成字符保持原样将数据打印到目的地
public class PrintDemo {
public static void main(String[] args) {
PrintStream out = new PrintStream("print.txt");
out.write(97); a
out.print(97); 97
}
}
PrintWriter
字符打印流
构造方法
- 字符串路径
- File对象
- 字节输出流
- 字符输出流
public class PrintWriterDemo {
public static void main(String[] args) {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
String line = null;
while((line = bufr.readLine())!=null) {
if("over".equals(line))
out.println(line.toUpperCase());
out.flush();
}
out.close();
bufr.close();
}
}
06-05-02 序列流
SequenceInputStream
作用:把其他输入流进行逻辑串联
构造方法
- SequenceInputStream(InputStream s1, InputStream s2)
低效率三个文件合成一个
public class SequenceInputStreamDemo {
public static void main() {
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);
}
fos.close();
sis.close();
}
}
高效率三个文件合成一个
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"));
// Enumeration<FileInputStream> en = v.elements();
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("1234.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
文件切割合并
文件切割
- 按照文件个数切
- 切成固定等分
- 按照文件大小切
- 切成固定大小
public class SplitFileDemo {
private static final int SIZE = 1024*1024;
public static void main(String[] args) {
File file = new File("c:\\0.bmp");
splitFile(file);
}
public static void splitFile(File file) {
//读取流关联文件
FileInputStream fis = new FileInputStream(file);
//定义一个1M的缓冲区
byte[] buf = new byte[SIZE];
//创建目的
FileOutputStream fos = null;
int len = 0;
int count = 1;
File dir = new File("c:\\partfiles");
if(!dir.exists())
dir.mkdirs();
while((len=fis.read(buf))!=-1) {
fos = new FileOutputStream(new File((count++)+".part"));
fos.write(buf,0,len);
}
fos.close();
fis.close();
}
}
文件合并
public class MergeFile {
public static void static main(String[] args) {
File dir = new File("c:\\partfiles");
mergeFile(fir);
}
}
public static void mergeFile(File dir) {
ArrayList<FileInputStream> a1 = new ArrayList<FileInputStream>();
for (int x = 1; x <= 3; x++) {
a1.add(new FileInputStream(new File(dir, x+".part")));
}
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream(new File(dir, "1.bmp"));
byte[] buf = new byte[1024];
int len = 0;
while((len = fos.read(buf))!= -1) {
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
文件切割合并
public class SplitFileDemo {
private static final int SIZE = 1024 * 1024;
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
File file = new File("c:\\aa.mp3");
splitFile_2(file);
}
private static void splitFile_2(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");
fos.close();
fis.close();
}
}
public static void mergeFile_2(File dir) throws IOException {
/*
* 获取指定目录下的配置文件对象。
*/
File[] files = dir.listFiles(new SuffixFilter(".properties"));
if(files.length!=1)
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();
}
06-05-03 ObjectStream
ObjectStream
- ObjectOutputStream
- ObjectOutputStream把Java对象的基本数据类型和图形通过序列化的方式写入硬盘
- ObjectInputStream
- ObjectInputStream可以通过反序列化的方式读取对象
序列化
- 对象通过序列化永久存储到硬盘,实现持久化
反序列化
- 通过反序列化读取硬盘上的对象进内存
注意
- 被序列化的对象的类必须实现Serializable接口
- Serializable是标记接口
- 一般扩展名为 .object
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException {
writeObj();
readObj();
}
public static void writeObj() throws IOException, ClassNotFoundException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
oos.writeObject(new Person("Steve", 30));
oos.close();
}
public static void readObj() throws IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInpuStream("obj.object"));
Person obj = (Person)ois.readObject();
System.out.println(p.getName()+":"+p.getAge());
}
}
Serializable接口
作用:用于给被序列化的类加入ID号(serialVersionUID)用于判断类和对象是否是同一版本
注意:如果不自定义UID,系统会默认使用UID,不过如果被序列化的对象的类被改变就会改变UID而导致无法被反序列化
自定义ID号
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
transient关键字 transient修饰的非静态数据,不可以被序列化
06-05-04 RandomAccessFile类
特点
- 该对象可以读写
- 该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素
- 可以通过getFilePointer方法获取指针的位置,通过seek方法设置指针的位置
- 该对象把字节输出流和输入流进行了封装
- 该对象的源和目的只能是文件
常见方法:
- 写入
- 如果文件不存在,则创建
- 如果文件存在,不创建
public class RandomAccessFileDemo {
public static void main(String[] args) {
writeFile();
}
//使用RandomAccessFile对象写入一些人员信息
public static void writeFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw");
raf.write("Tony".getBytes());
raf.write(97);
raf.write("Steve".getBytes());
raf.write(97);
raf.close();
}
public static void readFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("ranacc.txt","r");
//通过seek设置指针位置
ref.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);
raf.close();
}
}
随机写入
用seek方法设置写入位置
public static void randomWrite() throws IOException {
RandomAccessFile raf = new RandomAccessFile("ranacc.txt","r");
//从指定位置开始写入
raf.seek(3*8);//从第三个八位开始写
raf.write("Steve".getBytes());
raf.writeInt(102);
raf.close();
}
06-05-05 管道流
PipedStream
- PipedInputStream
- 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 {
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) {
// TODO: handle exception
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
Output(PipedOutputStream out){
this.out = out;
}
public void run(){
try {
Thread.sleep(5000);
out.write("hi,管道来了!".getBytes());
} catch (Exception e) {
// TODO: handle exception
}
}
}
06-05-06 DataStream
操作基本数据类型的流对象
public class DataSteamDemo {
/**
* @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);
}
public static void writeData() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("你好");
dos.close();
}
}
06-05-07 操作数组的流
操作字节数组的流
- ByteArrayStream
- ByteArrayInputStream
- ByteArrayOutputStream
操作字符数组的流
- CharArrayReader
- CharArrayWriter
操作字符串
- StringReader
- StreamWriter
ByteArrayStream
public class ByteArrayStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) {
ByteArrayInputStream bis = new ByteArrayInputStream("abcedf".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println(bos.toString());
}
}
06-05-08 编码表
常见的编码表
- ASCII:美国标准信息交换码
- 用一个字节的7位可以表示
- ISO8859-1:欧洲码表
- 用一个字节的8位表示
- GB2312:中国的中文编码表
- GBK:中国的中文编码表,融合了更多的中文符号
- Unicode:国际标准码表
- 所有文字都用两个字节来表示,Java语言就是用的Unicode
- UTF-8:8-bit Unicode Transformation Format最多用三个字节表示一个字符
简单的编码解码
- 字符串 –> 字节数组 编码
- 字节数组 –> 字符串 解码
public class EncodeDemo {
public static void main(String[] args) {
String str = "你好";
//你好:GBK -60 -29 -70 -61
//你好:UTF-8 -28 -67 -96 -27 -91 -67
//编码
byte[] buf = str.getBytes(“utf-8”);
printBytes(buf);
//解码
String s1 = new String(buf);
}
private static vodi printBytes(byte[] buf) {
for(byte b : buf) {
System.out.println(b);
}
}
}
public class EncodeDemo {
public static void main(String[] args) throws IOException {
/*
* 字符串 --> 字节数组:编码。
* 字节数组 --> 字符串:解码。
*
* 你好:GBK: -60 -29 -70 -61
*
* 你好: utf-8: -28 -67 -96 -27 -91 -67
*
* 如果你编错了,解不出来。
* 如果编对了,解错了,有可能有救。
*/
String str = "谢谢";
byte[] buf = str.getBytes("GBK");//用GBK编码
String s1 = new String(buf,"UTF-8");//用UTF-8解码
System.out.println("s1="+s1);//解码失败,用特殊编码表示原来的编码
byte[] buf2 = s1.getBytes("UTF-8");//获取源字节.
printBytes(buf2);
String s2 = new String(buf2,"GBK");//用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,"UTF-8");
System.out.println("s1="+s1);
}
private static void printBytes(byte[] buf) {
for(byte b : buf){
System.out.print(b +" ");
}
}
}
联通问题
联通这两个字的UTF-8和GBK的编码一样,所以导致GBK编码的联通系统会自动用UTF-8解码,导致乱码
public class LianTong {
public static void main(String[] args) throws IOException {
String str = "联通";
/*
11000001
10101010
11001101
10101000
*/
byte[] buf = str.getBytes("gbk");
for(byte b :buf){
System.out.println(Integer.toBinaryString(b&255));
}
}
}
按字节截取字符串
在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谢谢";
// str = "ab琲琲cd琲琲";
// int len = str.getBytes("gbk").length;
// for(int x=0; x<len; x++){
// System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByByte(str, x+1));
// }
int len = str.getBytes("utf-8").length;
for(int x=0; x<len; x++){
System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByU8Byte(str, x+1));
}
// String str = "琲";
// byte[] buf = str.getBytes("gbk");
// for(byte b : buf){
// System.out.println(b);//-84 105
// }
}
/*
*/
public static String cutStringByU8Byte(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)
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 cutStringByByte(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");
}
}