I O 流
一、IO流概述
1.什么是IO流
**IO流:**就是存储和读取数据的解决方案,用于读写文件中的数据(可以读写文件,或网络中的数据)
**思考:**IO流中,谁在读,谁在写?以谁为参照物看读写的方向呢===》程序
2.IO流的分类
(1)按IO流的方向分类
(2)按操作文件类型分类
3.小结:
(1)什么是IO流
存储和读取数据的解决方案
I:input O:output 流:像水流一样传输数据
(2)IO流的作用
用于读写数据(本地文件,网络)
(3)IO流按照流向可以分类哪两种流?
输出流:程序===》文件
输入流:文件===》程序
(4)IO流按照操作文件类型可以分类哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
(5)什么是纯文本文件
能被Windows自带的记事本打开并且能看懂的文件(.txt/.md/.xml/.lrc等)
二、IO流体系结构
1.结构
三、字节流
1.FileOutputStream
(1)作用:
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
(2)书写步骤:
①创建字节输出流对象
②写数据
③释放资源
import java.io.FileOutputStream;
import java.io.IOException;
public class _01_ByteStreamTest01 {
public static void main(String[] args) throws IOException {
/*(1)演示:字节输出流FileOutStream
实现需求:写一段文字到本地文件中(暂时不写中文)
(2)书写步骤:
①创建字节输出流对象
②写数据
③释放资源*/
//1.创建对象
FileOutputStream fos = new FileOutputStream("D:\\workspace\\idea_space\\Java_based\\study\\a.txt"); //括号里面指定文件写入的路径
//2.写出数据
fos.write(97);
//3.释放资源
fos.close();
}
}
(3)FileOutputStream的书写细节
字节输出流的细节:
1.创建字节输出流对象
细节1:参数是字符串表示的路径或者是File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但要保证父级路径是存在的
细节3:如果问价已经存在,则会清空文件
2.写数据
细节:write方法的参数是整数,但是实际上写道本地文件中的是整数再ASCII码表中对应的字符
3.释放资源
细节:每次使用完流都要释放资源
(4)FileOutputStream写数据的三种方式
方法名称 | 说明 |
---|---|
void write(int b) | 一次写一个字节数据 |
void write(byte[] b) | 一次写一个字节数组数据 |
void write(byte[] b,int off,int len) | 一次写一个字节数组的部分数据 |
import java.io.FileOutputStream;
import java.io.IOException;
public class _03_FileOutputStreamTest03 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileOutputStream fos = new FileOutputStream("D:\\workspace\\idea_space\\Java_based\\study\\b.txt");
//2.写入数据
//void write(int b) | 一次写一个字节数据
//fos.write(97);
//void write(byte[] b) | 一次写一个字节数组数据
byte [] arr = {97,98,99,100,101,102,103,105,106,107,108};
fos.write(arr); //abcdefgijkldefgij
//void write(byte[] b,int off,int len) | 一次写一个字节数组的部分数据
//参数一:数组
//参数二:起始索引
//参数三:个数
fos.write(arr,3,6); //defgij
//释放资源
fos.close();
}
}
(5)FileOutputStream写数据的两个小问题
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class _04_FileOutputStreamTest04 {
public static void main(String[] args) throws IOException {
/*
换行写:
再次写出一个换行符就可以了
windows: \r\n
Linux: \n
Mac: \r
细节:
在windows操作系统当中,java对回车换行进行了优化。
虽然完整的是\r\n,但是我们写其中一个\r或者\n,
java也可以实现换行,因为java在底层会补全。
建议:
不要省略,还是写全了。
续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件
*/
//1.创建对象
FileOutputStream fos = new FileOutputStream("D:\\workspace\\idea_space\\Java_based\\study\\b.txt",true);
//2.写出数据
String str = "geweikankelaoyehaoshuai";
byte[] bytes1 = str.getBytes();
System.out.println(Arrays.toString(bytes1));
fos.write(bytes1);
//换行写
String wrap = "\r\n";
byte[] bytes2 = wrap.getBytes();
fos.write(bytes2);
String str3 = "123123";
byte[] bytes3 = str3.getBytes();
fos.write(bytes3);
//3.释放资源
fos.close();
}
}
(6)小结
①FileOutputStream的作用
可以把程序中的数据写道本地文件上,是字节流的基本流
②书写步骤
创建对象,写出数据,释放资源
③三步操作的细节
★创建对象:文件存在(先清空再写入)、文件不存在(先创建,再写入,但要保证父级路径是存在的)、追加写入(创建对象时传递第二个参数true,表示打开续写开关)
★写出数据:写出整数(实际写出的是整数再ASCII码表对应的字符)、写出字节数组(将字符数组的全部或者部分内容写到文件当中)、换行写(写入换行符 windows:\r\n、Linux:\n、MacOS:\r)
★释放资源:关闭通道
2.FileInputStream
(1)作用:
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来
(2)书写步骤:
①创建字节输入流对象
②读取数据
③释放资源
public class _01_FileInputStreamTest01 {
public static void main(String[] args) throws IOException {
/*
* 演示:字节输入流FileInputStream
* 实现需求:读取文件中的数据。(暂时不写中文)
* 实现步骤:
* 创建对象
* 读取数据
* 释放资源
* */
//1.创建对象
FileInputStream fis = new FileInputStream("D:\\workspace\\idea_space\\Java_based\\study\\b.txt");
//2.读取数据
int b1 = fis.read();
System.out.println(b1); //97 返回字符再ASCII码表中对应的数字
//3.释放资源
fis.close();
}
}
(3)FileInputStream书写细节
1.创建字节输入流对象
细节1:如果文件不存在,就会直接报错
Java为什么会这么设计呢?
输出流:不存在,创建
把数据写到文件当中
输入流:不存在,而是报错呢?
因为创建出来的文件是没有数据的,没有任何意义。
所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。
程序中最重要的是:数据。
2.读取数据
细节1:一次读一个字节,读出来的是数据在ASCII码表上对应的数字
细节2:读到末尾了,read方法返回-1
3.释放资源
每一次使用完流之后,都要释放资源
(4)FileInputStream循环读取
import java.io.FileInputStream;
import java.io.IOException;
public class _03_FileInputStreamTest03 {
public static void main(String[] args) throws IOException {
/*
字节输入流循环读取
*/
//1.创建对象
FileInputStream fis = new FileInputStream("myio\\a.txt");
//2.循环读取
int b;
while ((b = fis.read()) != -1) {
System.out.println((char) b);
}
//3.释放资源
fis.close();
/* *//*
* 错误演示:不用变量接受数据会造成指针跳跃
* read :表示读取数据,而且是读取一个数据就移动一次指针
*
* *//*
FileInputStream fis = new FileInputStream("myio\\a.txt");
//2.循环读取
while ((fis.read()) != -1) {
System.out.println(fis.read());//98 100 -1
}
//3.释放资源
fis.close();*/
}
}
(5)文件拷贝
package com_08_IO._02FileInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class _04_FileInputStreamTest04 {
public static void main(String[] args) throws IOException {
/*
* 练习:
* 文件拷贝
* 把D:\itheima\movie.mp4拷贝到当前模块下。
*
* 注意:
* 选择一个比较小的文件,不要太大。大文件拷贝我们下一个视频会说。
*
*
*
* 课堂练习:
* 要求统计一下拷贝时间,单位毫秒
* */
long start = System.currentTimeMillis();
//1.创建对象
FileInputStream fis = new FileInputStream("D:\\workspace\\movie.mp4");
FileOutputStream fos = new FileOutputStream("D:\\workspace\\copy.mp4");
//2.拷贝
//核心思想:边读边写
int b;
while((b = fis.read()) != -1){
fos.write(b);
}
//3.释放资源
//规则:先开的最后关闭
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
(6)FileInputStream读取的问题
(7)FileInputStream一次读取多个字节
方法名称 | 说明 |
---|---|
public int read() | 一次读一个字节数据 |
public int read(byte[] buffer) | 一次读一个字节数组数据 |
**注意:**这种一次读取一个字节数组的数据,每次读取会尽可能吧数组装满
public class _05_FileInputStreamTest05 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fis = new FileInputStream("D:\\workspace\\idea_space\\Java_based\\study\\b.txt");
//2.读取数据
byte[] bytes = new byte[2];
//一次读取多个字节数据,具体读多少,跟数组的长度有关
//返回值:本次读取到了多少个字节数据
int len1 = fis.read(bytes);
System.out.println(len1);//2
String str1 = new String(bytes,0,len1);
System.out.println(str1);
int len2 = fis.read(bytes);
System.out.println(len2);//2
String str2 = new String(bytes,0,len2);
System.out.println(str2);
int len3 = fis.read(bytes);
System.out.println(len3);// 1
String str3 = new String(bytes,0,len3);
System.out.println(str3);// ed
//3.释放资源
fis.close();
}
}
3.try . . . catch 异常处理(捕获异常的完整形态)
(1)格式:
try{
}catch{
}finally{
//finally里面的代码一定会执行,除非虚拟机停止
}
(2)练习:
public class _06_FileInputStreamTest06 {
public static void main(String[] args) {
/* 利用try...catch...finally捕获拷贝文件中代码出现的异常* */
//1.创建对象
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:\\workspace\\movie.mp4");
fos = new FileOutputStream("D:\\workspace\\copy.mp4");
//2.拷贝
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
} catch (IOException e) {
//e.printStackTrace();
} finally {
//3.释放资源
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
(3)Java中提供的简化方式
在Java中提供了一个接口 AutoCloseable,只有在特定情况下,这个接口会自动释放资源
//JDK7
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class _07_FileInputStreamTest07 {
public static void main(String[] args) {
/* JDK7:IO流中捕获异常的写法
* try后面的小括号中写创建对象的代码,
* 注意:只有实现了AutoCloseable接口的类,才能在小括号中创建对象。
* try(){
*
* }catch(){
*
* }
* */
try(FileInputStream fis = new FileInputStream("D:\\workspace\\movie.mp4");
FileOutputStream fos = new FileOutputStream("D:\\workspace\\copy.mp4")){
//2.拷贝
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
//JDK9
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class _08_FileInputStreamTest08 {
public static void main(String[] args) throws FileNotFoundException {
/*
*
* JDK9:IO流中捕获异常的写法
*
*
* */
FileInputStream fis = new FileInputStream("D:\\workspace\\movie.mp4");
FileOutputStream fos = new FileOutputStream("D:\\workspace\\movie.mp4");
try (fis;fos) {
//2.拷贝
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、字符集
1.计算机的存储规则
在计算机中,任意数据都是以二进制的形式来存储的
(1)计算机存储英文
(2)计算机存储中文:
①GB2312字符集:
1980年发布,1981年5-1实施的简体中文汉字比编码国家标准,收录7445个图形字符,其中巴奥括6763个简体汉字
②BIG5字符集:
台湾地区繁体中文标准字符集,共收录13053个中文字,1984年实施
③GBK字符集:
2000年3月17日发布,收录21003个汉字。包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的而所有汉字,Windows系统默认使用的就是GBK,系统显示:
小结:
★在计算机中,任意数据都是以二进制数据的形式来存储的
★计算机中最小的存储单元是一个字节
★ASCII码表字符集中,一个英文占一个字节
★简体中文版Windows,默认使用GBK字符集
★GBK字符集完全兼容ASCII字符集
一个英文占一个字节,二进制第一位是0
一个中文占两个字符,二进制高位字节的第一位是1
④Unicode字符集:
国际标准字符集,它将世界各国语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息交换
总结
★Unicode字符集的UTF-8编码格式
一个英文占一个字节,二进制第一位是0,转成十进制是正数
一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
五、为什么会有乱码
原因1:
读取数据时未读完整个汉字
原因2:
编码和解码的方式不统一
1.如何才能不产生乱码?
(1)不要使用字节流读取文本文件
(2)编码解码使用同一个码表,同一个编码方式
2.扩展
(1)字节流读取中文会乱码,但是为什么拷贝不会乱码呢
因为拷贝和读取都是一个字节一个字节进行的,只要编码解码方式一样,就不会出现乱码
六、编码和解码
1.Java中编码的方式:
String类中方法名称 | 说明 |
---|---|
public byte[] getBytes() | 根据默认方式进行编码 |
public byte[] getBytes(String charsetName) | 根据指定方式进行编码 |
2.Java中解码的方式:
String类中方法名称 | |
---|---|
String (byte [] bytes) | 根据默认方式解码 |
String (byte [] bytes,String charsetName) | 根据指定方式解码 |
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class CharsetTest03 {
public static void main(String[] args) throws UnsupportedEncodingException {
//编码
String str = "ai你哟";
byte[] bytes1 = str.getBytes(); //idea默认使用utf-8 eclipse默认使用GBK编码
System.out.println(Arrays.toString(bytes1));
byte[] bytes2 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
//解码
String str1 = new String(bytes1);
System.out.println(str1);
String str2 = new String(bytes2,"GBK");
System.out.println(str2);
}
}
六、字符流
1.概述
(1)什么是字符流?
字符流的底层其实就是字节流
字符流 = 字节流 + 字符集
(2)特点:
输入流:一次读一个字节,遇到中文,一次读三个字节
输出流:底层会把数据按照指定编码方式的方式进行编码,变成字节再写到文件中
(3)使用场景
对纯文本文件进行操作
2.FileReader
(1)创建字符输入流对象
方法名称 | |
---|---|
public FileReader(File file) | 创建字符输入流关联本地文件 |
public FileReader(String getPathname) | 创建字符输入流关联本地文件 |
细节:如果文件不存在,会直接报错
(2)读取数据
方法名称 | 说明 |
---|---|
public int read() | 读取数据,都到末尾返回-1(按字节进行读取,遇到中文,一次读取多个字节,读取后解码,返回一个整数) |
public int read(char [] buffer) | 读取多个数据,读到末尾返回-1 |
(3)释放资源
方法名称 | 说明 |
---|---|
public int close() | 释放资源/关流 |
import java.io.FileReader;
import java.io.IOException;
public class CharsetStreamTest01 {
public static void main(String[] args) throws IOException {
//1.创建对象并关联本地文件
FileReader fr = new FileReader("D:\\workspace\\idea_space\\Java_based\\study\\b.txt");
//2.读取数据 read()
//字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
//如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节
//read()细节:
//1.read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
//2.在读取之后,方法的底层还会进行解码并转成十进制。
// 最终把这个十进制作为返回值
// 这个十进制的数据也表示在字符集上的数字
// 英文:文件里面二进制数据 0110 0001
// read方法进行读取,解码并转成十进制97
// 中文:文件里面的二进制数据 11100110 10110001 10001001
// read方法进行读取,解码并转成十进制27721
// 我想看到中文汉字,就是把这些十进制数据,再进行强转就可以了
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
//3.释放资源
fr.close();
}
}
//read含参构造
import java.io.FileReader;
import java.io.IOException;
public class CharsetStreamTest02 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileReader fr = new FileReader("myio\\a.txt");
//2.读取数据
char[] chars = new char[2];
int len;
//read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
//空参的read + 强转类型转换
while ((len = fr.read(chars)) != -1) {
//把数组中的数据变成字符串再进行打印
System.out.print(new String(chars, 0, len));
}
//3.释放资源
fr.close();
}
}
3.FileWriter
(1)FileWriter构造方法
方法名称 | 说明 |
---|---|
public FileWriter ( File file) | 创建字符输出流关联本地文件 |
public FileWriter(String pathname) | 创建字符输出流关联本地文件 |
public Fi了Writer(File file,boolean append) | 创建字符输出流关联本地文件,续写 |
public Fi了Writer(String pathname,boolean append) | 创建字符输出流关联本地文件,续写 |
(2)FileWriter成员方法
方法名称 | 说明 |
---|---|
void write(int c) | 写出一个字符 |
void write(String str) | 写出一个字符串 |
void write(String str,int off,int len) | 写出一个字符串的一部分 |
void write(char [] cubf) | 写出一个字符数组 |
void write(char [] cubf,int off,int len) | 写出一个字符数组的一部分 |
(3)FileWriter书写细节
①创建字符输出流对象
★细节1:参数是字符串表示的路径或者是File对象都是可以的
★细节2:如果文件按不存在会创建一个新的文件,但要保证腹肌路径是存在的
★细节3:如果文件存在,则会清空文件,如果不想清空,可以打开续写开关
②写数据
★如果write方法的参数是整数,但是实际上写到本地文件中的是整数再字符集上对一个的字符
③释放资源
★每次使用完流之后,都要释放资源
public class CharsetStreamTest03 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\workspace\\idea_space\\Java_based\\study\\b.txt",true);
//void write(int c) | 写出一个字符 |
fw.write(25105);//根据字符集的编码方式将参数表示的字符进行编码,把编码之后的数据写道文件中取
//void write(String str) | 写出一个字符串 |
fw.write("你好坏啊,我好喜欢");
//void write(String str,int off,int len) | 写出一个字符串的一部分
fw.write("你好坏啊我好喜欢",2,4);
//void write(char [] cubf) | 写出一个字符数组
char [] chars = {'我','是','中','国','人'};
fw.write(chars);
//void write(char [] cubf,int off,int len) | 写出一个字符数组的一部分
fw.write(chars,2,3);
fw.close();
}
}
4.字符流原理分析
(1)字符输入流的底层原理
①创建字符输入流对象:
底层:关联文件,并创建缓冲区(长度位8192的字节数组)
②读取数据
底层:
①判断缓冲区是否有数据可以读取
②如果缓冲区没有数据,会从文件直接获取,装到缓冲区,每次尽可能地装满缓冲区,如果文件也没有数据,返回-1
③如果缓冲区有数据,从缓冲区直接获取,英文每次获取一个字节,中文每次获取三个字节,把字节解码并转成十进制返回(有参的read方法会把读取,解码,强转合并,将强转之后的字符放到数组中),直到缓冲区没有数据,再次从文件获取,如果文件中也没有数据了,那么返回-1
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CharsetStreamTest04 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\workspace\\idea_space\\Java_based\\study\\b.txt");
fr.read();//会把文件中的数据放到缓冲区当中
//清空文件
FileWriter fw = new FileWriter("D:\\workspace\\idea_space\\Java_based\\study\\b.txt");
//请问,如果我再次使用fr进行读取
//会读取到数据吗?
//会把缓冲区中的数据全部读取完毕
//正确答案:
//但是只能读取缓冲区中的数据,文件中剩余的数据无法再次读取
int ch;
while((ch = fr.read()) != -1){
System.out.println((char)ch);
}
fw.close();
fr.close();
}
}
(2)字符输出流的底层原理
5.字节流和字符流的使用场景
(1)字节流
★拷贝任意类型的文件
(2)字符流
★读取纯文本文件中的数据
★往纯文本文件中写出数据
七、练习
1.需求:拷贝一个文件夹,考虑子文件夹
细节:如果listFiles获取的文件夹是带有权限的,那么方法返回null,
package com_08_IO.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test01 {
public static void main(String[] args) throws IOException {
//1.创建对象表示数据源
File file1 = new File("D:\\aaa");
//2.创建对象表示目的地
File file2 = new File("D:\\bbb");
//3.调用方法拷贝文件
copyFile(file1,file2);
}
/*
* 作用:拷贝文件夹
* 参数一:数据源
* 参数二:目的地
* */
private static void copyFile(File file1, File file2) throws IOException {
file2.mkdirs();
/*递归
* 1.进入数据源
* 2.遍历数组
* 3.判断文件,拷贝
* 4.判断文件夹,递归*/
//进入数据源
File[] listFiles = file1.listFiles();
//遍历数组
for (File file : listFiles) {
if(file.isFile()){
//判断文件,拷贝
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File(file2,file.getName()));
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}else{
copyFile(file,new File(file2,file.getName()));
}
}
}
}
2.需求:
为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理,
加密原理:对原始文件中的每一个字节数据进行更改,然后将更改以后的数据存储到新的文件中
解密原理:读取加密之后的文件,按照加密的原则反向操作,变成原始文件
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test02 {
public static void main(String[] args) throws IOException {
/*
^ : 异或
两边相同:false
两边不同:true
0:false
1:true
100:1100100
10: 1010
1100100
^ 0001010
__________
1101110
^ 0001010
__________
1100100
*/
//加密
FileInputStream fis = new FileInputStream("D:\\aaa\\1.png");
FileOutputStream fos = new FileOutputStream("D:\\bbb\\1.png");
int b;
while((b = fis.read()) != -1){
fos.write(b ^ 2);
}
//fos.close();
//fis.close();
//解密:
FileInputStream fis1 = new FileInputStream("D:\\bbb\\1.png");
FileOutputStream fos1 = new FileOutputStream("D:\\bbb\\2.png");
int c;
while((c = fis.read()) != -1){
fos.write(c ^ 2);
}
fos.close();
fis.close();
}
}
3.需求:
文本文件中有以下数据:2-1-9-4-7-8
将文件的数据进行排序,变成以下的数据:1-2-4-7-8-9
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Test03 {
public static void main(String[] args) throws IOException {
//1.读取文件中的数据
FileReader fr = new FileReader("D:\\aaa\\a.txt");
StringBuilder sb = new StringBuilder();
int b;
while ((b = fr.read()) != -1) {
sb.append((char) b);
System.out.println(b);
}
fr.close();
System.out.println(sb);
//排序
String str = sb.toString();
String[] arrStr = str.split("-");
ArrayList<Integer> list = new ArrayList<>();
for (String s : arrStr) {
int i = Integer.parseInt(s);
list.add(i);
}
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(list);
//写出数据
FileWriter fw = new FileWriter("D:\\aaa\\a.txt");
for (int i = 0; i < list.size(); i++) {
if (i < list.size()-1){
fw.write(list.get(i)+"-");
}else{
fw.write(list.get(i)+"");
}
}
fw.close();
}
}
简化写法:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
public class Test04 {
public static void main(String[] args) throws IOException {
/* 3.需求:
文本文件中有以下数据:2-1-9-4-7-8
将文件的数据进行排序,变成以下的数据:1-2-4-7-8-9
*/
//1.读取文件中的数据
FileReader fr = new FileReader("D:\\aaa\\a.txt");
StringBuilder sb = new StringBuilder();
int b;
while ((b = fr.read()) != -1) {
sb.append((char) b);
System.out.println(b);
}
fr.close();
System.out.println(sb);
//排序
/*Integer[] arr = Arrays.stream(sb.toString().split("-")).map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).sorted().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr));*/
//简化
Integer[] arr = Arrays.stream(sb.toString()
.split("-"))
.map(Integer::parseInt)
.sorted()
.toArray(Integer[]::new);
System.out.println(Arrays.toString(arr));
//写出数据
FileWriter fw = new FileWriter("D:\\aaa\\a.txt");
String str = Arrays.toString(arr).replace(", ","-");
fw.write(str.substring(1,str.length()-1));
fw.close();
}
}
细节:
1.文件中的数据不要换行,否则读取文件会读取到换行符
2.有些文本文件带有bom头,可能会导致排序失败