赞
踩
java基础io流——OutputStream和InputStream的故事(温故知新) https://www.jianshu.com/p/63d1751d3eac
java基础io流——字符流的变革(深入浅出) https://www.jianshu.com/p/9f3fd98ec28b
IO流用来处理设备之间的数据传输,上传文件和下载文件,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中。
按照数据流向
输入流 读入数据
输出流 写出数据
按照数据类型
字节流
字符流
什么情况下使用哪种流呢?
如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流,其他用字节流。
如果你什么都不知道,就用字节流。
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
OutputStream的子类FileOutputStream
构造方法:
FileOutputStream(File file)
FileOutputStream(String name)
推荐第二种构造方法:
FileOutputStream outputStream = new FileOutputStream("a.txt");
创建字节输出流对象了做了几件事情:
- A:调用系统功能去创建文件
- B:创建outputStream对象
- C:把foutputStream对象指向这个文件
通过字节输出流写出数据到文本
- public void write(int b)
- public void write(byte[] b)
- public void write(byte[] b,int off,int len)
从方法中可看出,只能通过字节写出
- outputStream.write("hello".getBytes()); 文本中出现hello
- outputStream.write(96) //文本中出现 a
-
- byte[] bys={97,98,99,100,101};
- outputStream.write(bys,1,3); 文本中出现bcd
如此写出,文本中数据不会换行,不会追加,每次写出都是覆盖原来。
追加:
- FileOutputStream outputStream = new FileOutputStream("a.txt",true);
- //第二个参数true设置为可追加。
换行 \n\r :
- for (int i = 0; i <5 ; i++) {
- outputStream.write("hello".getBytes());
- outputStream.write("\n\r".getBytes());
- }
注:用完流一定要记得关闭。
outputStream.close();
完整示例:
- package io2;
-
- import java.io.FileOutputStream;
- import java.io.IOException;
- /**
- * new FileOutputStream("a.txt",true); 第二个参数true,设置为写入的数据拼接在尾部
- * \n\r 换行
- * write(bys,1,3); 写入字节数组
- */
- public class out {
- public static void main(String args[]){
- FileOutputStream outputStream = null;
- try {
- //FileOutputStream fos = new FileOutputStream(file);
- outputStream = new FileOutputStream("a.txt",true);
- /*
- * 创建字节输出流对象了做了几件事情:
- * A:调用系统功能去创建文件
- * B:创建outputStream对象
- * C:把foutputStream对象指向这个文件
- */
-
- // for (int i = 0; i <5 ; i++) {
- // outputStream.write("hello".getBytes());
- // outputStream.write("\n\r".getBytes());
-
- // }
- byte[] bys={97,98,99,100,101};
- outputStream.write(bys,1,3);
- } catch (IOException e) {
- e.printStackTrace();
- }
- finally {
- try {
- outputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-
- }
- }
-
FileInputStream的构造方法
- FileInputStream(File file)
- FileInputStream(String name)
推荐第二种构造方法:
FileInputStream inputStream = new FileInputStream("a.txt");
把刚才写的数据现在读取到控制台:
- public int read()
- public int read(byte[] b)
第一个read是读一个字节,第二个read是读一个字节数组。
- //读一个字节
- int by = 0;
- while ((by=inputStream.read())!=-1){
- System.out.println((char)by);
- }
读到没数据了就返回-1,这个用来判断是否读完。
- //读一个字节数组,一般是1024大小
- int len = 0 ;
- byte[] bys = new byte[1024];
- while ((len = inputStream.read(bys)) != -1) {
- System.out.println(new String(bys,0,len));
- }
两个read的返回值略有不同,read()返回读取的字节,读到末尾返回-1,read(byte[] b)返回的是读到的字节个数,读到的字节放在了bytes字节数组里,读到末尾没数据了返回-1。
两种读取方式图解:
同样的用完了流,也要及时的关闭,以防占用内存。
inputStream.close();
完整示例:
建议以字节数组的方式读取数据。
- package io2;
-
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
-
- /**
- * Create by stefan
- * Date on 2018-05-27 23:00
- * Convertion over Configuration!
- */
- public class input2 {
- public static void main(String args[]){
- FileInputStream inputStream = null;
- try {
- inputStream = new FileInputStream("a.txt");
- // byte[] bys = new byte[4];
- // int len = inputStream.read(bys);
- // System.out.println(new String(bys)); //bcd
- // System.out.println(len); //3
- // System.out.println(inputStream.read(bys)); //-1
- int len = 0 ;
- byte[] bys = new byte[1024];
- while ((len = inputStream.read(bys)) != -1) {
- System.out.println(new String(bys,0,len));
- }
- /**
- * public String(byte bytes[]) {
- this(bytes, 0, bytes.length);
- }
- */
-
- } catch (IOException e) {
- e.printStackTrace();
- }finally {
- try {
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- }
- }
-
利用输入流读取一个文件里的字节,再利用输出流将读取到的字节写出到另一个文件中(不存在会自动创建)
- package io2;
-
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.Arrays;
-
- /**
- * Create by stefan
- * Date on 2018-05-27 23:19
- * Convertion over Configuration!
- */
- public class copy {
- public static void main(String args[]) throws IOException {
- FileInputStream inputStream = new FileInputStream("E:\\huge1.jpg");
- FileOutputStream outputStream = new FileOutputStream("E:\\古月.jpg");
-
- byte[] bytes = new byte[1024];
- int len = 0;
- while ((len=inputStream.read(bytes)) != -1) {
- outputStream.write(bytes,0,len);
- outputStream.flush();
- }
- inputStream.close();
- outputStream.close();
- }
- }
-
注:复制文本、图片、mp3、视频等的方式一样。
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果。
java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流。
- 字节缓冲输出流
- BufferedOutputStream
- 字节缓冲输入流
- BufferedInputStream
BufferedOutputStream
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt",true));
- bos.write("hello world".getBytes());
- bos.close();
BufferedInputStream
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
- byte[] bytes = new byte[1024];
- int len = 0;
- while ((len=bis.read(bytes)) != -1) {
- System.out.println(new String(bytes,0,len));
- }
- bis.close();
注:
复制文件的升级:
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\modern-java.pdf"));
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:\\汤包\\慕课大巴\\modern-java.pdf"));
- int len = 0;
- byte[] bytes =new byte[1024];
- while ((len=bis.read(bytes)) != -1) {
- bos.write(bytes,0,len);
- bos.flush();
- }
- bis.close();
- bos.close();
测试:四种复制文件的效率高低
- package io2;
-
- import java.io.*;
-
- /**
- *
- * 测试复制的时间
- * Create by stefan
- * Date on 2018-05-28 10:28
- * Convertion over Configuration!
- */
- public class copy2 {
- //一个字节一个字节的复制,耗时22697毫秒
- public static void fun() throws IOException {
- FileInputStream fis = new FileInputStream("F:\\汤包\\慕课大巴\\modern-java.pdf");
- FileOutputStream fos = new FileOutputStream("E:\\modern-java.pdf");
- int by = 0;
- while ((by=fis.read()) != -1) {
- fos.write(by);
- fos.flush();
- }
- fis.close();
- fos.close();
- }
- //1024字节数组复制 耗时63毫秒
- public static void fun1() throws IOException {
- FileInputStream fis = new FileInputStream("F:\\汤包\\慕课大巴\\modern-java.pdf");
- FileOutputStream fos = new FileOutputStream("E:\\modern-java.pdf");
- int len = 0;
- byte[] bytes =new byte[1024];
- while ((len=fis.read(bytes)) != -1) {
- fos.write(bytes,0,len);
- fos.flush();
- }
- fis.close();
- fos.close();
- }
- // 一个字节一个字节复制,但是用了缓冲流 耗时64毫秒
- public static void fun2() throws IOException {
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\modern-java.pdf"));
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:\\汤包\\慕课大巴\\modern-java.pdf"));
- int by = 0;
- while ((by=bis.read()) != -1) {
- bos.write(by);
- bos.flush();
- }
- bis.close();
- bos.close();
- }
- // 1024字节数组复制并用了缓冲流 耗时7毫秒
- public static void fun3() throws IOException {
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\modern-java.pdf"));
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:\\汤包\\慕课大巴\\modern-java.pdf"));
- int len = 0;
- byte[] bytes =new byte[1024];
- while ((len=bis.read(bytes)) != -1) {
- bos.write(bytes,0,len);
- bos.flush();
- }
- bis.close();
- bos.close();
- }
-
- public static void main(String args[]) throws IOException {
- long t1 = System.currentTimeMillis();
- fun3();
- long t2 = System.currentTimeMillis();
- System.out.println(t2-t1);
- }
-
- }
-
经测试结果显示:
1024字节数组复制并用了缓冲流 的方式效率最高。
在io流里,先诞生了字节流,但是字节流读取数据会有乱码的问题(读中文会乱码)。比如:
- FileInputStream fis = new FileInputStream("a.txt");
- // int by = 0;
- // while ((by=fis.read() )!= -1) {
- // System.out.print((char)by);//bcdbcdbcdbcdbcdbcdhello ä¸å�½
- // //因为还正常,中文就乱码了,有什么办法解决吗,有,就是有点麻烦
- // }
从文件中读取中文会有乱码,当然字节流有解决措施。
- FileInputStream fis = new FileInputStream("a.txt");
- byte[] bytes = new byte[1024];
- int len = 0;
- while ((len = fis.read(bytes)) != -1) {
- System.out.println(new String(bytes,0,len));//bcdbcdbcdbcdbcdbcdhello 中国
- //查看new String()的源码,this.value = StringCoding.decode(bytes, offset, length);
- //点进decode,循序渐进发现,默认编码是UTF-8
- //通过源码,也看到了这个方法public String(byte bytes[], int offset, int length, String charsetName)
-
- }
但是解码这并不是字节流做的,而是String的功能。查看String的源码,构造方法有解码功能,并且默认编码是utf-8。
聊到了乱码,我觉得有必要聊一下编码的知识。
- String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
- byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
-
- 编码:把看得懂的变成看不懂的
- String -- byte[]
-
- 解码:把看不懂的变成看得懂的
- byte[] -- String
因此字节流读取的数据是编码过的数据,我们解码就行了。
编码问题简单,只要编码解码的格式是一致的。
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。
- ASCII:美国标准信息交换码。
- 用一个字节的7位可以表示。
- ISO8859-1:拉丁码表。欧洲码表
- 用一个字节的8位表示。
- GB2312:中国的中文编码表。
- GBK:中国的中文编码表升级,融合了更多的中文文字符号。
- GB18030:GBK的取代版本
- BIG-5码 :通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。
- Unicode:国际标准码,融合了多种文字。
- 所有文字都用两个字节来表示,Java语言使用的就是unicode
- UTF-8:最多用三个字节来表示一个字符。
-
- UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:
- 它将Unicode编码为00000000-0000007F的字符,用单个字节来表示�
- 它将Unicode编码为00000080-000007FF的字符用两个字节表示
- 它将Unicode编码为00000800-0000FFFF的字符用3字节表示
示例:
- String s = "你好";
- byte[] bytes1 = s.getBytes();
- System.out.println(Arrays.toString(bytes1));//[-28, -67, -96, -27, -91, -67] 默认编码utf-8
-
- byte[] bytes2 = s.getBytes("GBK");
- System.out.println(Arrays.toString(bytes2));//[-60, -29, -70, -61]
- byte[] bytes3 = s.getBytes("UTF-8");
- System.out.println(Arrays.toString(bytes3));//[-28, -67, -96, -27, -91, -67]
-
- String s1 = new String(bytes1);
- System.out.println(s1);//你好
- String s2 = new String(bytes2,"GBK");
- System.out.println(s2);//你好
-
- String s3 = new String(bytes2,"gbk");
- System.out.println(s3);//你好
-
- String s4 = new String(bytes3);
- System.out.println(s4);//你好
-
- String s5 = new String(bytes3,"gbk");
- System.out.println(s5);//浣犲ソ
虽然字节流有解决乱码的方案,但并不方便,所以java io流就设计出了转换流,一场乱码引发的变革。
(OutputStreamWriter、InputStreamReader)
OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流
OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
把字节流转换为字符流。
- //创造对象
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));//查看源码,java8 默认utf-8
- //写数据
- osw.write("中国");
- //释放资源
- osw.close();//close包含了close和flush的作用
一般默认编码就够了。
查看源码,发现OutputStreamWriter有5个write方法。
- /*
- * OutputStreamWriter的方法:
- * public void write(int c):写一个字符
- * public void write(char[] cbuf):写一个字符数组
- * public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
- * public void write(String str):写一个字符串
- * public void write(String str,int off,int len):写一个字符串的一部分
- *
- * 面试题:close()和flush()的区别?
- * A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。
- * B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。
- */
-
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c.txt"));//查看源码,java8 默认utf-8
- //写一个字符
- osw.write('a');
- osw.write(97);
- osw.write('中');
- // 为什么数据没有进去呢?
- // 原因是:字符 = 2字节
- // 文件中数据存储的基本单位是字节。
- // void flush()
- osw.flush();
- //写一个字符数组
- char[] chars = {'a','b','中','国'};
- osw.write(chars);
- osw.flush();
- //写一个字符数组的一部分
- osw.write(chars,2,2);
- osw.flush();
- //写一个字符串
- osw.write("\n\r中国");
- //写一个字符串的一部分
- osw.write("中国你好",2,2);
- osw.close();
InputStreamReader(InputStream is):用默认的编码读取数据,默认utf-8
InputStreamReader(InputStream is,String charsetName):
用指定的编码读取数据
- //创建对象
- InputStreamReader isr = new InputStreamReader(new FileInputStream("b.txt"));//默认编码utf-8
- InputStreamReader isr1 = new InputStreamReader(new FileInputStream("b.txt"),"gbk");//可指定编码
-
- //读数据
- int ch = 0;
- while ((ch = isr.read()) != -1) {
- System.out.print((char)ch);//中国
- }
- //释放资源
- isr.close();
- //只有文档的编码和读取的编码一致才不会乱码。
查看源码知道InputStreamReader有2个read方法。
- /*
- * InputStreamReader的方法:
- * int read():一次读取一个字符
- * int read(char[] chs):一次读取一个字符数组
- */
- InputStreamReader isr = new InputStreamReader(new FileInputStream("c.txt"));
- //读一个字符
- // int ch = 0;
- // while ((ch = isr.read()) != -1) {
- // System.out.print((char) ch);//9797200139798200132226920013222691020013222692032022909/
- // //aa中ab中国中国
- // //中国你好
- // }
- //isr.close();
- //读一个字符数组
- char[] chars =new char[1024];
- int len = 0;
- while ((len = isr.read(chars)) != -1) {
- System.out.println(chars.length);//1024
- System.out.println(new String(chars,0,len));
- //aa中ab中国中国
- //中国你好
- }
- isr.close();
现在我们可以通过转换流升级字节流复制文件的方式了。
- InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("e:\\a.txt"));
- char [] chars = new char[1024];
- int len = 0 ;
- while ((len = isr.read(chars)) != -1) {
- osw.write(chars,0,len);
- osw.flush();
- }
- osw.close();
- isr.close();
转换流已经是字符流了,但是他们的名字太长了,Java就提供了其子类供我们使用。
FileWriter 、FileReader 继承了其父类的所有方法。
字符流=字节流+编码表
OutputStreamWriter = FileOutputStream + 编码表(GBK)
FileWriter = FileOutputStream + 编码表(GBK)
InputStreamReader = FileInputStream + 编码表(GBK)
FileReader = FileInputStream + 编码表(GBK)
复制改写:
- FileWriter fw = new FileWriter("e:\\b.txt");
- FileReader fr = new FileReader("b.txt");
- char[] chars =new char[1024];
- int len = 0;
- while ((len = fr.read(chars)) != -1) {
- fw.write(chars,0,len);
- fw.flush();
- }
- fw.close();
- fr.close();
- /**
- * 总结,到现在为止,加上字节流,复制文本的方式有8种,但是复制图片视频等文件只有四种字节流的方式,因为不能用字符流复制图片视频mp3等
- */
字符流学习前辈字节流的经验,也设计了字符缓冲流。
BufferedReader、
BufferedWriter
和字节缓冲流的设计基本一样,也有两个构造方法,但是我们只要默认的缓冲大小的构造方法就可以了。
用字符缓冲流改写复制功能:
- BufferedReader br = new BufferedReader(new FileReader("c.txt"));
- BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\d.txt"));
- char[] chars = new char[1024];
- int len = 0 ;
- while ((len = br.read(chars)) != -1) {
- bw.write(chars,0,len);
- bw.flush();
- }
- br.close();
- bw.close();
然而字符缓冲流还有自己特殊的读写功能。
BufferedWriter :void newLine() 换行
BufferedReader :String readLine() 读一行数据
- public static void main(String args[]) throws IOException {
- // write();
- read();
- }
-
- private static void read() throws IOException {
- BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
- String line = null;
- while ((line = br.readLine()) != null) {
- System.out.println(line);
- //readLine不会读取换行符
- //读到末尾返回null
- }
- br.close();
- }
-
- private static void write() throws IOException {
- BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
- for (int i = 0; i <10 ; i++) {
- bw.write("你好哈哈哈哈哈");
- bw.newLine();//换行,并且自动检测不同系统的换行符
- bw.flush();
- //一般三个连用
- }
- bw.close();
- }
用字符缓冲流的特殊方式升级复制功能:
- BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
- BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\bw.txt"));
-
- String line = null;
- while ((line = br.readLine()) != null) {
- bw.write(line);
- bw.newLine();
- bw.flush();
- }
- bw.close();
- br.close();
-
-
- //总结 字符流复制文本有5种方式
字符流的基础基本就聊完了,还有一个比较常用的类LineNumberReader
查看源码可知LineNumberReader继承自BufferedReader,并且增加了行号的操作。
- LineNumberReader lnr = new LineNumberReader(new FileReader("a.txt"));
- String line = null;
- while ((line = lnr.readLine()) != null) {
- System.out.println(lnr.getLineNumber()+":"+line);
- }
-
- 1:A
- 2:S
- 3:F
但是LineNumberWriter。源码很简单,更多的操作请看源码。
https://blog.csdn.net/weixin_41547486/article/details/79917815
3. 可以使用自动刷新。只有在调用println、printf或者format的其中一个方法时才可能完成此操作。
- 使用字符打印流向文件中写入数据
- public class PrintDemo {
- public static void main(String[] args) {
- PrintWriter pw = null;
-
- try {
-
- //创建字符打印流对象
-
- pw = new PrintWriter("e.txt");
-
- //向文件中分别打印boolean、字符、int、字符串
-
- pw.print(true);
-
- pw.print('a');
-
- pw.print(12);
-
- pw.print("李昆鹏");
-
- //刷新
-
- pw.flush();
-
- } catch (FileNotFoundException e) {
-
- e.printStackTrace();
-
- }finally {
-
- //字符打印流也是需要关闭的,但是不用处理异常
-
- if(pw != null)
-
- pw.close();
-
- }
-
- }
- }
- 从文件中读取数据并且打印在控制台
- public class PrintDemo2 {
- public static void main(String[] args) {
-
- BufferedReader br = null;
-
- PrintWriter pw = null;
-
- try {
-
- //创建高效缓冲区字符输入流对象
-
- br = new BufferedReader(new FileReader("Student.txt"));
-
- //创建打印流对象
-
- //pw = new PrintWriter(System.out);
-
- //设置自动刷新的打印流在文件对象后面加true
-
- pw = new PrintWriter(System.out,true);
-
- String line = null;
-
- while((line = br.readLine()) != null) {
-
- pw.println(line);
-
- //当使用自动刷新构造器时就不需要手动刷新
-
- //pw.flush();
-
- }
-
- } catch (FileNotFoundException e) {
-
- e.printStackTrace();
-
- } catch (IOException e) {
-
- e.printStackTrace();
-
- }finally {
-
- try {
-
- if(br != null)
-
- br.close();
-
- if(pw != null)
-
- pw.close();
-
- } catch (IOException e) {
-
- e.printStackTrace();
-
- }
-
- }
-
- }
- 范例:使用打印流来复制文本文件
-
- public class PrintDemo3 {
-
- public static void main(String[] args) {
-
- BufferedReader br = null;
- PrintWriter pw = null;
-
- try {
-
- //创建高效缓冲区字符输入流对象
-
- br = new BufferedReader(new FileReader("Student.txt"));
-
- //创建打印流对象
-
- //pw = new PrintWriter(System.out);
-
- //设置自动刷新的打印流在文件对象后面加true
-
- pw = new PrintWriter(new FileWriter("Student1.txt"));
-
- String line = null;
-
- while((line = br.readLine()) != null) {
-
- pw.println(line);
-
- //当使用自动刷新构造器时就不需要手动刷新
-
- //pw.flush();
-
- }
-
- } catch (FileNotFoundException e) {
-
- e.printStackTrace();
-
- } catch (IOException e) {
-
- e.printStackTrace();
-
- }finally {
-
- try {
-
- if(br != null)
-
- br.close();
-
- if(pw != null)
-
- pw.close();
-
- } catch (IOException e) {
-
- e.printStackTrace();
-
- }
-
- }
-
- }
-
- }
-
-
- 打印字符串中
- StringWriter sw = null;
- PrintWriter pw = null;
-
- try {
- sw = new StringWriter();
- pw = new PrintWriter(sw);
- e.printStackTrace(pw);
- pw.flush();
- sw.flush();
- } catch (Exception var12) {
- ;
- } finally {
- if(sw != null) {
- try {
- sw.close();
- } catch (Exception var11) {
- ;
- }
- }
-
- if(pw != null) {
- pw.close();
- }
-
- }
-
- String str = sw.toString();
- return str.substring(0, str.length() - 1 > 300?300:str.length() - 1);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。