javaIO流-字符流-字符缓冲流-

编码表

为什么出现字符流

  • 一个汉字存储:
    如果是GBK编码,占用2个字节
    如果是UTF-8编码,占用3个字节
  • 字节流读取字符数据会出现问题,比如使用UTF-8编码的汉字,一个汉字占用3个字节,如果字节一个一个读取,没有办法拼成汉字。
  • 由于字节流操作中文不是特别方便,所以java提供了字符流。字符流 = 字节流 + 编码表
  • 用字节流复制文本文件时,文本文件也会有中文,但是没有问题,
    原因是:最终底层操作会自动进行字节拼接成中文,如何识别是中文呢?汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数。

字符集

  • 计算机中存储的信息都是用二进制数表示的,我们在屏幕上看到的英文、汉字等字符是二进制转换之后的结果
  • 按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。注意,按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号,否则就会导致乱码现象。
  • 字符编码:就是一套自然语言的字符与二进制数之间的对应规则(A,65)
  • 字符集:是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等;计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集。

ASCII字符集:

  • ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
  • 基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

GBXXX字符集:

  • GB2312:简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字。此外数学符号、罗马希腊的字母、日文的假名等都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的“全角”字符,而原来在127号以下的那些就叫“半角”字符了。
  • GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。其中GB2312标准下两个字节都多于0x7f才可以表示一个汉字;
  • GB18030:最新的中文码表,收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。

Unicode字符集:

  • 为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。它最多使用4个字节的数字来表达每个字母、符号、或者文字。有三种编码方案:UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
  • UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码。
  • 编码规则:①128个US-ASCII字符,只需一个字节编码;②拉丁文的等字符,需要二个字节编码;③大部分常用字(含中文),使用三个字节编码;④其他极少使用的Unicode辅助字符,使用四字节编码。

字符串中的编码解码问题

编码: 按照字符集将String编码为字节存放到字节数组中

方法名说明
byte[] getBytes()使用平台默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName)使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

解码: 按照字符集用字节数组构造新的String

方法名说明
String(byte[] bytes)
String构造方法
通过使用平台的默认字符集解码指定的字节数组来构建新的String
String(byte[] bytes,String charsetName)
String构造方法
通过指定的字符集解码指定的字节数组来构建新的String
static String toString(byte[] a)
Arrays的静态方法
返回指定数组的内容的字符串表示形式

案例:编解码测试

// 37
public class Demo2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //定义一个字符串
        String s = "中国";
        // 编码
        byte[] bys = s.getBytes();
        // 输出内容是:[-28, -72, -83, -27, -101, -67]

	# 说明:
//        byte[] bys = s.getBytes("UTF-8");
        // 使用这个方法 需要抛出一个异常,throws UnsupportedEncodingException
        // 输出结果是:[-28, -72, -83, -27, -101, -67]
        // 说明idea中编码方式默认是UTF-8

//        byte[] bys = s.getBytes("GBK");
        // 输出结果是:[-42, -48, -71, -6]
        System.out.println(Arrays.toString(bys));


        // 解码
//        String ss = new String(bys);
        // 输出是 中国 编码解码采用的都是idea默认的字符集UTF-8
     # 说明:
        String ss = new String(bys,"GBK");
        // 输出是 涓浗 由于编码解码不匹配 所以导致输出结果和原本文件不一致
        System.out.println(ss);    
    }
}

字符流

字符流中编解码问题

字符流抽象基类:

类名说明
Reader字符输入流的抽象类
Writer字符输出流的抽象类

字符流中和编码解码问题相关的两个类:

说明InputStreamReaderOutputStreamWriter
所属包在java.io包下,使用的时候需要导包在java.io包下,使用的时候需要导包
含义从字节流到字符流的桥梁:它读取字节,并使用指定的charset将其解码为字符。
它使用的字符集可以由名称指定(即被明确指定),或者可以接收平台的默认字符集。
从字符流到字节流的桥梁:它读取字符,并使用指定的charset将其编码为字节。
它使用的字符集可以由名称指定(即被明确指定),或者可以接收平台的默认字符集。

字符流中的方法介绍

方法名说明
OutputStreamWriter(OutputStream out)创建一个使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out,String charsetName)创建一个使用命名字符集的OutputStreamWriter
InputStreamReader (InputStream in)创建一个使用默认字符集的InputStreamReader
InputStreamReader(InputStream in,String charsetName)创建一个使用命名字符集的InputStreamReader
FileWriter (String name)创建一个使用默认字符编码的OutputStreamWriter
FileReader (String name)创建一个使用默认字符编码的InputStreamReader

为了便捷书写,使用简化字符流名称

转换流名对应子类名说明
InputStreamReaderFileReader(String fileName)用于读取字符文件的便捷类
OutputStreamWriterFileWriter(String fileName)用于写入字符文件的便捷类

案例:

// 37-Demo3 
public class Demo3 {
    public static void main(String[] args) throws IOException {

/*        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\osw.txt"));
        osw.write("中国");
        osw.close();*/
* 说明:
        // OutputStreamWriter 和 write 方法都是用默认编码方式,写入文件的内容是 中国

        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\osw.txt"),"GBK");
        osw.write("中国");
        osw.close();
* 说明:
        //OutputStreamWriter 采用GBK方式解码 , write用默认编码方式 UTF-8,写入文件的内容是 乱码 
        // 查看OutputStreamWriter 类中的write方法,没有参数可以设置编码方式。

* 说明:
//        InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\osw.txt"));
// 输出结果 得到乱码,因为编码是 GBK 解码采用默认方式UTF-8

* 说明:
        InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\osw.txt"),"GBK");
        // 输出结果 是中国。

        // 一次读取一个字符数据
        int ch;
        while((ch = isr.read()) != -1){
            System.out.print((char)ch);
        }

        isr.close();
    }
}

字符流写数据(数组/字符串)

方法名说明
void write(int c)写一个字符
void write(char[] cbuf)写人一个字符数组
void write(char[] cbuf,int off,int len)写入字符数组的一部分,从off开始,长度为len的数组
void write(String str)写一个字符串
void write(String str,int off,int len)写一个字符串的一部分

案例:

// 37
public class Demo4 {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\osw.txt"));

# 说明:
        // write(char c) 写一个字符
        osw.write(97);
       // 视频中这样的形式没有将字符写入文件,但是自己操作时却可以将此字符写入。原因是写了osw.close()这个内容。
       // 这里我们采用的是字符流写数据,不能直接将字符写入文件,因为它最终需要通过字节流去写数据的,现在它还存在于缓冲区中,通过使用 方法 void flush() 可以将数据从缓冲区中直接写入到文件中去。
# 说明:
       void flush():刷新流
      //  为什么不使用flush刷新流但是字符可以写进去,原因是:close方法是先刷新,再关闭流。
       // 释放资源close方法已经使用了,之后是不能再写数据了。

* 说明:
        // write(char[] cbys):写一个字符数组
        char[] cbys = {'a','b','c','d','e'};
//        osw.write(cbys);

* 说明:
        // write(char[] cbys,int offset,int len):写一个字符数组的一部分
//        osw.write(cbys, 0, 3);
* 说明:
        //write(String str):写一个字符串
//        osw.write("xhjab");
* 说明:
        // write(String str,int offset,int len):写一个字符串的一部分
        osw.write("abcxhj", 3, 3);

        // 释放资源
        osw.close();
    }
}

注意

2022/4/14
通过字符流写数据,最终还是要通过字节流去写数据的。
字符流写数据不能直接写在文件中,而是先在缓冲区中,可以通过flush方法写入文件中
也可以不使用flush方法,而是在字符流写数据结束的时候 使用close方法,该方法会先执行flush、再关闭流

字符流读数据(数组)

方法名说明
int read()一次读一个字符数据
int read(char[] cbug)一次读一个字符数组数据

理解
字符流读数据的read操作只匹配字符流写数据写一个字节/字节数组/字节数组的一部分。write(int by)、write(byte[] bytes),write(byte[] bytes,int off,int len)

案例:

// 37-Demo5 
public class Demo5 {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\test.txt"));
# 说明:
        // int read() :一次读取一个字符
/*        int ch;
        while((ch = isr.read()) != -1){
            System.out.print((char)ch);
        }*/
# 说明:
        // int read(char[] cbuf):一次读取一个字符数组
        char[] cbuf = new char[1024];
        int len;
        while((len = isr.read(cbuf)) != -1){
            System.out.println(new String(cbuf,0,len));
        }

        isr.close();
    }
}

字符流读写数据模板

1 创建字符流输入流对象、字符输出流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(文件路径));
OutputStreamWriter isw = new OutputStreamWriter(new FileOutputStream(文件路径));

2 一次读写一个字节
int by;
while((by = isr.read()) != -1){
	osw.write(by);
	// 控制台输出
	System.Output.println((char)by);
}

3 一次读写一个字符数组
char[] chs = new char[1024];
int len;
while((len = isr.read(chs)) != -1){
	osw.write(chs);
	osw.write(chs,o,len);
}

4 字符流关闭
isr.close();
osw.close();
案例:复制java文件

需求:把模块目录下的“xxx”复制到模块目录下的“xxx”

// 37-Demo6 
public class Demo6 {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\Demo5.java"));

        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\copy.java"));

        // 读一个字符写一个字符
/*        int ch;
        while ((ch = isr.read()) != -1) {
            osw.write(ch);
        }*/

        // 一次读写一个字符数组数据
        char[] chs = new char[1024];
        int len;
        while((len = isr.read(chs)) != -1){
            osw.write(chs,0,len);
        }
        isr.close();
        osw.close();
    }
}
案例:复制java文件(改进版FileReader、FileWriter)

需求:把模块目录下的“xxx”复制到模块目录下的“xxx”
分析:转换流的名字较长,为了方便书写,提供了对应的子类。

转换流名对应子类名说明
InputStreamReaderFileReader(String fileName)用于读取字符文件的便捷类
OutputStreamWriterFileWriter(String fileName)用于写入字符文件的便捷类

化简过程

//源地址:原地址路径--读数据--Reader--InputStreamReader--FileReader
InputStreamReader isr = new InputStreamReader(new FileInputStream("文件路径"));
FileReader fr = new FileReader("文件路径");

//目的地址:目的地址路径--写数据--Writer--OutputStreamWriter--FileWriter
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("文件路径"));
FileWriter fw = new FileWriter("文件路径");

案例:

// 37-Demo7 
public class Demo7 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader(".\\Demo5.java");

        FileWriter fw = new FileWriter(".\\copy.java");

        char[] chs = new char[1024];
        int len;
        while((len = fr.read(chs)) != -1){
            fw.write(chs,0,len);
        }

        fr.close();
        fw.close();
    }
}

字符缓冲流

输入流/输出流

介绍字符缓冲输入流字符缓冲输出流
名字BufferedReaderBufferedWriter
解释从字符输入流读取文本,缓冲字符,以提供字符、数组和行的高效读取。
可以指定缓冲区大小,或者可以使用默认大小,默认值足够大。
将文本写入字符输出流,缓冲字符,以提供单个字符、数组和字符串的高效写入。
可以指定缓冲区大小,或者可以接受默认大小,默认值足够大。
类声明public class BufferedReader extends Readerpublic class BufferedWriter extends Writer
构造方法BufferedReader(Reader in)BufferedWriter (Writer out)

读数据和写数据
读数据:read(int by) read(byte[] byte)
写数据:write(int by)、write(byte[] bytes)、write(byte[] bytes,int off,int len)、write(String str)、write(String str,int off,int len)

案例:

// 37
public class Demo8 {
    public static void main(String[] args) throws IOException {
/*        BufferedWriter rw = new BufferedWriter(new FileWriter(".\\rw.txt"));

        rw.write("sciens\r\n");
        rw.write("technology\r\n");

        rw.close();*/

        BufferedReader br = new BufferedReader(new FileReader(".\\rw.txt"));

        // 一次读写一个字符
/*        int ch;
        while((ch = br.read()) != -1){
            System.out.print((char)ch);
        }*/
        System.out.println("--------------");
        
        
        // 一次读取一个字符数组
        char[] chs = new char[1024];
        int len;
        while((len = br.read(chs)) != -1){
            System.out.print(new String(chs,0,len));
        }
        br.close();
    }
}

案例:复制java文件(字符缓冲流改进版)

需求:把模块目录下的“xxx”复制到模块目录下的“xxx”
代码:

// 37
public class Demo9 {
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new FileReader(".\\Demo5.java"));

        BufferedWriter bw = new BufferedWriter(new FileWriter(".\\copy.java"));

/*        int ch;
        while((ch = br.read()) != -1){
            bw.write((char)ch);
        }*/

        char[] chs = new char[1024];
        int len;
        while((len = br.read(chs)) != -1){
            bw.write(chs,0,len);
        }

        br.close();
        bw.close();
    }
}

字符缓冲流特有功能

所属类方法名说明
BufferedWritervoid newLine()写一行 行分隔符,行分割符字符串由系统属性定义
BufferedReaderpublic String readLine()读一行文字,结果包含行的内容的字符串,不包含任何行终止字符,如果流的结尾已经到达,则为null
感觉这个属性是为了配合OutputStreamWriter类中的Writer的写字符串的方法

使用字符缓冲流写数据特殊功能的步骤:

1 创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new fileReader("文件路径"));
2 创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new fileWriter("文件路径"));
3 使用readLine读取一行文字,并写入字符输出流对象。
String line;
while((line = br.readline())!= null) {
	bw.write(line);
	bw.newLine();
	bw.flush();
	}

案例:复制java文件(readLine)

代码:

// 38-
public class Demo2 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(".\\Demo5.java"));

        BufferedWriter bw = new BufferedWriter(new FileWriter(".\\copy.java"));

        String line;
        while((line = br.readLine()) != null){
            bw.write(line);
            // 单使用readLine方法,读取不会读入换行符之类的内容。写入的内容都在一行中。
            bw.newLine();
            bw.flush();
        }

        br.close();
        bw.close();
    }
}

注意

2022/4/14
单独使用readLine方法读取数据 不会读入换行符之类的内容,换行需要执行newLine方法

字符流案例

案例1:集合到文件(基本数据)

需求:
把ArrayList集合中的字符串数据写入到文本文件。

要求:
一个字符串元素作为文件中的一行数据。

思路

1 创建ArrayList<String> 集合
	ArrayList<String> array = new ArrayList<String>();
	array.add("集合元素");
2 创建字符缓冲输出流对象
	BufferedWriter bw = new BufferedWriter(new FileWriter("文件路径"));
3 使用增强for循环遍历集合,集合元素写入文件中write方法
	for(String s:array){
		fw.write(s);
		//一个字符串作为一行数据
		fw.newLine();
		fw.flush();
		}
4 释放资源
	fw.close();

代码:

// 38
public class Demo3 {
    /*
    需求:把ArrayList集合中的字符串数据写入到文本文件。
    要求:一个字符串元素作为文件中的一行数据。
    */
    public static void main(String[] args) throws IOException {
        // 创建ArrayList集合
        ArrayList<String> array = new ArrayList<String>();

        //集合添加元素
        array.add("sensors");
        array.add("application");
        array.add("keyboard");

        // 创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter(".\\test38.txt"));

        // 遍历集合得到每一个字符串
        for(String st:array){
            bw.write(st);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        bw.close();
    }
}

案例2:文件到集合

需求:
把文本文件中的数据读取到集合中,并遍历集合。

要求:
文件中每一行数据是一个集合元素(说明要使用BufferedReader的特殊方法readLine)

思路

1 创建ArrayList集合
	ArrayList<String> array = new ArrayList<String>();
2 创建字符缓冲输入流对象
	BufferedReader br = new BufferedReader(new FileReader("文件路径"));
3 使用方法readLine读取一行数据,并使用add方法添加到集合中
	String line;
	while((line = br.readline()) != null){
		array.add(line);
	}
4 释放字符流资源
	br.close();
5 遍历集合 采用迭代器遍历
	Iterator<String> it = array.iterator();
	while(it.hasNext()){
		System.out.println(it.next());
		}

代码:

// 38-
public class Demo4 {
    public static void main(String[] args) throws IOException {
        // 创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader(".\\test38.txt"));

        // 创建ArrayList集合
        ArrayList<String> array = new ArrayList<String>();

        // 读数据 使用特有方法readLine
        String ss;
        while((ss = br.readLine()) != null){
            array.add(ss);
        }
        
        // 释放资源
        br.close();

        // 遍历集合
        for(String st:array){
            System.out.println(st);
        }
    }
}

案例3:点名器ArrayList+random

需求:
一个文件里面存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随机点名器

思路:

1 创建字符缓冲流输入流对象,将一行数据读入ArrayList集合
	BufferedReader br = new BufferedReader(new FileReader("文件路径"));
	ArrayList<String> array = new ArrayList<String>();
	String line;
	while((line = br.readLine()) != null){
		array.add(line);
		}
	br.close();
	
2 产生随机数,随机数是[0,array.size()),通过get(index)方法得到对应的值
	Random r = new Random();
	int x = r.nextInt(array.size());
	System.out.println(array.get(x));
//38-
public class Demo5 {
    public static void main(String[] args) throws IOException {
        // 创建字符缓冲输入流对象

        BufferedReader br = new BufferedReader(new FileReader(".\\test38.txt"));
        // 创建ArrayList集合
        ArrayList<String> array = new ArrayList<String>();

        // 通过br读取文件中的内容
        String line;
        while((line = br.readLine()) != null){
            // 读取后的数据存储在集合中
            array.add(line);
        }

        // 释放资源
        br.close();

        // 用Random产生一个随机数 表示随机点名
        Random r = new Random();
        int index = r.nextInt(array.size());

        // 产生的随机数 作为索引在集合中找对应的值并输出
        System.out.println("幸运者是:"+array.get(index));

    }
}

不太记得内容是:

1 使用Random产生一个随机数
Random r = new Random();
2 产生一个[0,array.size())的随机数
int index = r.nextInt(array.size());
3 通过索引号找集合中的元素
array.get(index);

案例4:集合到文件(数据=对象)

需求:
把ArrayList集合中的学生数据写入到文本文件。

要求:
每一个学生对象的数据作为文件中的一行数据

格式是:学号,姓名,年龄,居住地 举例:001,Bob,30,西安
思路

1 创建ArrayList集合并添加学生对象
	ArrayList<Student> array = new ArrayList<Student>();
	array.add(学生对象);
2 创建字符缓冲输出流对象
	BufferedWriter bw = new BufferedWriter(new FileWriter("文件路径"));
3 遍历集合,将集合元素按照指定格式存放到文件中
	for(Student stu : array){
		StringBuilder sb = new StringBuilder();
		sb.append(stu.getXXX()).append(",").append(stu.getXXX()).append(",");
	}
	bw.write(sb.toString());
	bw.flush();
	bw.close();
		

代码:

// 38-
public class Demo6 {
    public static void main(String[] args)  throws IOException {
        /*  需求:把ArrayList集合中的学生数据写入到文本文件。
            要求:每一个学生对象的数据作为文件中的一行数据
            格式是:学号,姓名,年龄,居住地  举例:001,Bob,30,西安
            */

        // 创建ArrayList集合
        ArrayList<Student> array = new ArrayList<Student>();
        // 创建学生对象
        Student st1 = new Student(001,"汪苏泷",33,"西安");
        Student st2 = new Student(002,"许嵩",30,"西安");
        Student st3 = new Student(003,"白敬亭",31,"西安");

        // 将学生对象添加到集合中
        array.add(st1);
        array.add(st2);
        array.add(st3);
        // 创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter(".\\test38.txt"));

        // 遍历集合,将每一个学生信息写入文件中
        for(Student st:array){
            // 这种形式不对。书写的学号和年龄是乱码
/*            bw.write(st.getNum());
            bw.write(",");
            bw.write(st.getName());
            bw.write(",");
            bw.write(st.getAge());
            bw.write(",");
            bw.write(st.getLocal());
            bw.newLine();
            bw.flush();*/

            StringBuilder sb = new StringBuilder();
            sb.append(st.getNum()).append(",").append(st.getName()).append(",").append(st.getAge()).append(",").append(st.getLocal());

            bw.write(sb.toString());
            bw.newLine();
            bw.flush();
        }
        // 释放资源
        bw.close();

    }
}

案例5:文件到集合(数据=对象)

需求:
把文本文件中的数据读取到集合中,并遍历集合。

要求:
文件中的每一行数据是一个学生对象的成员变量。举例:001,汪苏泷,30,西安。
思路

1 创建字符缓冲输入流对象
	BufferedReader br = new BufferedReader(new FileReader("文件路径"));
2 创建集合对象
	ArrayList<Student> array = new ArrayList<Student>();
3 使用readLine读取数据,将读取的字符串采用split分割,然后创建学生对象,并对所有值进行设置setXXX方法 最后学生元素添加到集合中
	String line;
	while((line = br.readline())!= null){
		String[] strs = line.split(',');
		Student st = new Student();
		st.setId(Integer.parseInt.(strs[0]));
		// 使用Integer.parseInt方法将字符串转为int类型
		st.setName(strs[1]);
		st.setAge(Integer.parseInt.(strs[2]));
		st.setAddress(strs[3]);
		array.append(st);
		}
4 遍历集合
 使用增强for循环	

代码:

// 38
public class Demo7 {
    public static void main(String[] args) throws IOException {

        /*
        需求:把文本文件中的数据读取到集合中,并遍历集合。
        要求:文件中的每一行数据是一个学生对象的成员变量。举例:001,汪苏泷,30,西安。
        */

        // 创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader(".\\test38.txt"));


        // 创建ArrayList集合
        ArrayList<Student> array = new ArrayList<Student>();

        // 使用字符缓冲输入流对象的读数据方法
        String line;
        while((line = br.readLine()) != null){

            //将得到字符串使用split进行分割,得到一个字符串数组
            String[] sArray = line.split(",");

            // 创建学生对象
            Student st = new Student();
            st.setNum(Integer.parseInt(sArray[0]));
            st.setName(sArray[1]);
            st.setAge(Integer.parseInt(sArray[2]));
            st.setLocal(sArray[3]);

            array.add(st);
        }

        // 释放资源
        br.close();

        // 遍历集合
        for(Student s : array){
            System.out.println(s.getNum() + "," + s.getName() + "," + s.getAge() + "," + s.getLocal());
        }
    }
}

案例6:集合到文件(数据排序TreeSet)

需求:
键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)。

要求:
按照学生成绩总分从高到低写入文本文件。

格式:
姓名,语文成绩,数学成绩,英语成绩 举例:汪苏泷,98,99,100

思路:

1 创建键盘录入学生信息的函数
	public void writeInformation(TreeSet set){
		Scanner sc = new Scanner(System.in);
		Student stu = new Student();
		String name = sc.nextLine();
		int score0 = sc.nextInt();
		int score1 = sc.nextInt();
		int score2 = sc.nextInt();
		stu.setName(name);
		stu.setScore0(score0);
		stu.setScore1(score1);
		stu.setScore2(score2);
		set.add(stu);
	}
2 创建TreeSet集合 并按照总分从高到低排序,总分相同 按照语文成绩排序 依次是数学、姓名
TreeSet<Student> setTree = new TreeSet<Student>(new comparator<Student>{
	@Override
	public int compare(Student s1,Student s2){
		// 总分从高到低
		int num = s1.getSum() - s2.getSum();
		
		// 次要条件
		int num1 = num ==0 ? s1.getChinese()-s2.getChinese() : num;
		int num2 = num1 ==0 ? s1.getMath()-s2.getMath() : num1;
		int num3 = num2 == 0 ? s1.getName()-s2.getName(): num2;
		return num3;
	}
})

3 创建字符缓冲输出流对象 将集合数据写入文件中
	BufferedWriter bw = new BufferedWriter(new FileWriter("文件路径"));
	for(Student stu : setTree){
		StringBuilder sb = new StringBuilder();
		sb.append(stu.getName()).append(",").append(stu.getChinese()).append(",").append(stu.getMath()).append(",").append(stu.getEnglish());
		bw.write(sb.toString());
		bw.newLine();
		bw.flush();
	}
	bw.close();
// 
public class Demo {
    public static void main(String[] args) throws IOException {
                /*需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)。
要求:按照学生成绩总分从高到低写入文本文件
格式:姓名,语文成绩,数学成绩,英语成绩      举例:汪苏泷,98,99,100
*/
        // 创建学生类

        // 创建TreeSet集合 通过比较器排序进行排序
        TreeSet<Student> tSet = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                // 正数 将要存储的数据 放于 现存数据 之后
                // 待存数据 s1 现存数据 s2

                // 成绩总分从高到低
                int num = s2.getSum() - s1.getSum();

                // 次要条件
                int num2 = num==0?s1.getChineseScore() - s2.getChineseScore():num;
                int num3 = num2==0?s1.getMathScore() - s2.getMathScore():num2;
                int num4 = num3==0?s1.getName().compareTo(s2.getName()):num3;

                return num4;
            }
        });


        // 键盘录入学生信息
        for(int i = 0;i<5;i++){
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第" + (i+1) + "个学生信息");
            System.out.println("姓名:");
            String name = sc.nextLine();
            System.out.println("语文成绩:");
            int chinese = sc.nextInt();
            System.out.println("数学成绩:");
            int math = sc.nextInt();
            System.out.println("英语成绩:");
            int english = sc.nextInt();
            // 创建学生对象
            Student st = new Student();
            st.setName(name);
            st.setChineseScore(chinese);
            st.setMathScore(math);
            st.setEnglishScore(english);

            // 将学生信息添加到集合中
            tSet.add(st);
        }
        // 创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter(".\\test3.txt"));
        // 遍历TreeSet集合,将学生信息按照指定格式拼接成字符串,将集合中内容写入文件。
        for(Student st : tSet){
            StringBuilder sb = new StringBuilder();
            sb.append(st.getName()).append(",").append(st.getChineseScore()).append(",").append(st.getMathScore()).append(",").append(st.getEnglishScore()).append(",").append(st.getSum());

            // 调用字符缓冲输出流对象的方法写数据
            bw.write(sb.toString());
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        bw.close();

    }
}

案例7:复制单级文件夹

单级文件夹 = 文件夹中只有文件而没有目录。

需求:
把“xxx”这个文件夹复制到模块目录xxx下。

public class Demo {
    public static void main(String[] args) throws IOException {
        // 创建数据源目录的File对象
        File fSrc = new File("E:\\222\\javaSE");

        // 获取数据源目录file对象的名称 也就是javaSE
        String fName = fSrc.getName();

        // 创建目的地目录file对象,路径名是模块名 + fName组成
        File fDes = new File(".\\",fName);

        // 判断目的地目录对应的file是否存在,如果不存在,就创建
        if(!fDes.exists()){
            fDes.mkdir();
//            System.out.println("创建成功");
        }
        // 获取数据源目录下的所有文件的File数组
        File[] srcfiles = fSrc.listFiles();
        
        // 遍历File数组,得到每一个file对象,该file对象,其实就是数据源文件
        for(File srcfile:srcfiles){
            // 获取每一个数据文件的名字
            String srcfileName = srcfile.getName();
//            System.out.println(srcfileName);
            // 创建目的地文件file对象
            File desfile = new File(fDes,srcfileName);
//            String path = desfile.getPath();
//            System.out.println(path);
            // 复制文件
            copyfile(srcfile,desfile);
        }

//        System.out.println(fName);
    }

    // 复制文件方法
    private static void copyfile(File srcfile, File desfile)throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcfile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(desfile));

//        int[] num =new int[1024];
        // 这里是字节数组 byte
        byte[] bys = new byte[1024];
        int len;
        while((len = bis.read(bys)) != -1){
            bos.write(bys, 0, len);
        }

        bis.close();
        bos.close();
    }
}

案例8:复制多级文件夹(需要使用到递归)

多级文件夹 = 文件夹 里 还有文件夹。

需求:把“xxx”复制到某盘目录下

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 创建数据源路径 file对象
        File srcFile = new File("E:\\222");

        // 创建数据目的路径 组合 源路径名字的 file对象
        File destFile = new File("c:\\");

        // 写方法实现文件夹的复制
        copyFolder(srcFile,destFile);

    }
    // 复制文件夹
    private static void copyFolder(File srcFile,File destFile) throws IOException{
        // 判断数据源是否是目录
        if(srcFile.isDirectory()){
            // 是目录
            // 在目的地址下创建和数据源file名称一样的目录
            String srcFileName = srcFile.getName();
            File newFolder = new File(destFile,srcFileName);

            if(!newFolder.exists()){
                newFolder.mkdir();
            }

            // 获取数据源file下的所有文件或者目录的file数组
            File[] filesArray = srcFile.listFiles();
            for(File fi : filesArray){
                copyFolder(fi,newFolder);
            }
        }else{
            // 说明是文件,直接复制,用字节流
            File newdestFile = new File(destFile,srcFile.getName());
            copyFile(srcFile, newdestFile);
        }
    }

    // 字节缓冲流复制文件
    private static void copyFile(File srcfile,File desfile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcfile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(desfile));

        byte[] bys = new byte[1024];
        int len;
        while((len = bis.read(bys)) != -1){
            bos.write(bys, 0, len);
        }
        bis.close();
        bos.close();
    }
}

案例9:复制文件的异常处理

try…catch…finally的做法:

try{
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}finally{
	执行所有清除操作;
}

JDK7改进方案:

try(定义流对象){
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}

自动释放资源

JDK9改进方案:

定义输入流对象;
定义输出流对象;
try(输入流对象;输出流对象){
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}

自动释放资源

案例:

public class Demo3 {
    public static void main(String[] args) {
    }
    // 在方法外面抛出异常 throws IOException
    public static void method1() throws IOException {
        FileReader fr = new FileReader("test38.txt");
        FileWriter fw = new FileWriter("fw.txt");

        char[] chs = new char[1024];
        int len;
        while((len = fr.read(chs)) != -1){
            fw.write(chs, 0, len);
        }

        fr.close();
        fw.close();
    }

    // try..catch..finally..
    public static void method2(){
        FileReader fr = null;
        FileWriter fw = null;
        try{
            fr = new FileReader("test38.txt");
            fw = new FileWriter("fw.txt");

            char[] chs = new char[1024];
            int len;
            while((len = fr.read(chs)) != -1){
                fw.write(chs, 0, len);
            }

        }catch(IOException e){
            e.printStackTrace();
        }finally{
            if(fr != null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // JDK7 改进方案
    public static void method3(){

        try(FileReader fr = new FileReader("test38.txt");
            FileWriter fw = new FileWriter("fw.txt");){
            char[] chs = new char[1024];
            int len;
            while((len = fr.read(chs)) != -1){
                fw.write(chs, 0, len);
            }

        }catch(IOException e){
            e.printStackTrace();
        }
    }

    // JDK9 的改进方案
    public static void method4() throws IOException{
        FileReader fr = new FileReader("test38.txt");
        FileWriter fw = new FileWriter("fw.txt");
        try(fr;fw){
            char[] chs = new char[1024];
            int len;
            while((len = fr.read(chs)) != -1){
                fw.write(chs, 0, len);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

字符流总结

说明ReaderWriter
转换流 将字节流转为字符流InputStreamReader(InputStream is)OutputStreamWriter(OutputStream os)
简化转化流书写FileReader(String filename)FileWriter(String filename)
字符缓冲流BufferedReader(Reader reader)BufferedWriter (Writer writer)

注意
简化的转换流 参数只支持String类型;

Scanner

概述
public final class Scanner extends Object implements Iterator< String>,closeable
一个简单的文本扫描器,可以使用正则表达式解析原始类型和字符串。

常用方法

方法介绍
Scanner(InputStream source)Scanner sc = new Scanner(System.in);
构造一个新的Scanner,产生从指定的输入流扫描的值
int nextInt()将输入的下一个标记扫描为int
String nextLine()将此扫描仪推进到当前行并返回跳过的输入。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值