8、IO
8.2 IO流
8.2.4 IO流常用基类-字节流
读取一个键盘录入的数据,并打印在控制台上。
键盘本身就是一个标准的输入设备。对于java而言,对于这种输入设备都有对应的对象。
示例3:
- import java.io.IOException;
- import java.io.InputStream;
- public class ReadKey{
- public static void main(String[] args) throws IOException {
- readKey();
- }
- public static void readKey() throws IOException {
- InputStream in = System.in;
- int ch = in.read();//阻塞式方法
- System.out.println(ch);
- ch = in.read(); //阻塞式方法
- System.out.println(ch);
- ch = in.read(); //阻塞式方法
- System.out.println(ch);
-
- in.close();
- }
- }
复制代码 运行结果:
P.S.
1、获取键盘录入数据,然后将数据流向显示器,那么显示器就是目的地。
通过System类的setIn,setOut方法可以对默认设备进行改变。
System.setIn(new FileInputStream(“1.txt”));//将源改成文件1.txt。
System.setOut(new PrintStream(“2.txt”));//将目的改成文件2.txt
因为是字节流处理的是文本数据,可以转换成字符流,操作更方便。
BfferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw =
new BufferedWriter(new OutputStreamWriter(System.out));
2、默认的输入和输出系统不需要关,它会随着系统的结束而消失。
练习:
获取用户键盘录入的数据并将数据变成大写显示在控制台上,如果用户输入的是over,结束键盘录入。
思路:
1. 因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串。
2. 那就需要一个容器:StringBuilder。
3. 在用户回车之前将录入的数据变成字符串判断即可。
代码:
- import java.io.IOException;
- import java.io.InputStream;
- public class ReadKey{
- public static void main(String[] args) throws IOException {
- readKey();
- }
- public static void readKey() throws IOException {
- //1、创建容器
- StringBuilder sb = new StringBuilder();
- //2、获取键盘读取流
- InputStream in = System.in;
- //3、定义变量记录读取到的字节,并循环获取
- int ch = 0;
- while((ch = in.read()) != -1){
- //在存储之前需要判断是否是换行标记,因为换行标记不存储
- if(ch == '\r' )
- continue;
- if(ch == '\n' ){
- String temp = sb.toString();
- if("over" .equals(temp))
- break;
- System.out.println(temp.toUpperCase());
- sb.delete(0,sb.length());
- } else{
- //将读取到的字节存储到StringBuilder中
- sb.append(( char)ch);
- }
- }
- }
- }
复制代码 运行结果: 8.2.5 转换流
转换流的由来:
字符流与字节流之间的桥梁
方便了字符流与字节流之间的操作
转换流的应用:
字节流中的数据都是字符时,转成字符流操作更高效。
转换流:
InputStreamReader:字节到字符的桥梁,解码。
OutputStreamWriter:字符到字节的桥梁,编码。
InputStreamReader是字节流通向字符流的桥梁。
示例1:
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- 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);
-
- String line = null;
- //读取到了字符串数据
- while((line = bufr.readLine()) != null){
- if("over" .equals(line))
- break;
- System.out.println(line.toUpperCase());
- }
- }
- }
复制代码 运行结果:
P.S.
使用字节流读取一个中文字符需要读取两次,因为一个中文字符由两个字节组成,而使用字符流只需读取一次。
System.out的类型是PrintStream,属于OutputStream类别。
OutputStreamReader是字符流通向字节流的桥梁。
示例2:
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.io.OutputStreamWriter;
- 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);
-
- //字节流,字节数据
- OutputStream out = System.out;
- //数据到了osw,目的地out控制台
- OutputStreamWriter osw = new OutputStreamWriter(out);
- BufferedWriter bufw = new BufferedWriter(osw);
- String line = null;
- while((line = bufr.readLine()) != null){
- if("over" .equals(line))
- break;
-
- //将字符数据用缓冲区对象将数据写入缓冲区,目的地是osw
- bufw.write(line.toUpperCase());
- bufw.newLine();
- //osw.write(line.toUpperCase() + "\r\n");可以替代上面两行代码
- bufw.flush();
- }
- }
- }
复制代码 运行结果:
以上代码可以简化为:
示例3:
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- public class TransStreamDemo{
-
- public static void main(String[] args) throws IOException {
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
-
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- String line = null;
- while((line = bufr.readLine()) != null){
- if("over" .equals(line))
- break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- }
- }
复制代码 运行结果:
需求:将键盘录入的数据写入到一个文件中。
代码:
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.FileOutputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- import java.io.IOException;
- public class TransStreamDemo{
-
- public static void main(String[] args) throws IOException {
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
- String line = null;
- while((line = bufr.readLine()) != null){
- if("over" .equals(line))
- break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- }
- }
复制代码 运行结果:
需求:将一个文本文件内容显示在控制台上。
代码:
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- public class TransStreamDemo{
-
- public static void main(String[] args) throws IOException {
- BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
- String line = null;
- while((line = bufr.readLine()) != null){
- if("over" .equals(line))
- break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- }
- }
复制代码 运行结果:
需求:将一个文本文件中的内容复制到另一个文件中。
代码:
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- public class TransStreamDemo{
-
- public static void main(String[] args) throws IOException {
- BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
-
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
- String line = null;
- while((line = bufr.readLine()) != null){
- if("over" .equals(line))
- break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- }
- }
复制代码 运行结果:
8.2.6 流的操作规律
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道对象的开发时用到哪些对象,只要通过四个明确即可。
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
3、明确具体的设备
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4、是否需要其他额外功能
是否需要高效(缓冲区):
是,就加上buffer
需求1:复制一个文本文件
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本?
是!
源:Reader
目的:Writer
3、明确具体设备。
源:
硬盘:File
目的:
硬盘:File
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
4、需要额外功能吗?
需要,高效
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
============================================
需求2:读取键盘录入信息,并写入到一个文件中
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本?
是!
源:Reader
目的:Writer
3、明确具体设备。
源:
键盘:System.in
目的:
硬盘:File
FileReader fr = new System.in;
FileWriter fw = new FileWriter("b.txt");
这样做可以完成,但是麻烦。将读取的字节数据转成字符串,再由字符流操作。
4、需要额外功能吗?
需要,转换。将字节流转成字符流,因为明确的源是Reader,这样操作文本数据更快捷。
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:将一个文本文件数据显示在控制台上
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本?
是!
源:Reader
目的:Writer
3、明确具体设备。
源:
硬盘:File
目的:
硬盘:System.out
FileReader fr = new FileReader("a.txt");
FileWriter fw = System.out;//PrintStream
4、需要额外功能吗?
需要,转换。
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:读取键盘录入数据,显示在控制台上
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本?
是!
源:Reader
目的:Writer
3、明确具体设备。
源:
键盘:System.in
目的:
控制台:System.out
InputStream in = System.in;
OutputStream out = System.out;
4、明确额外功能?
需要,转换。因为都是字节流,但是操作的却是文本数据。所以使用字节流操作起来更为便捷。
InputSreamReader 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));
练习:将一个中文字符串数据按照指定的编码表写入到一个文本文件中。
1、目的:OutputStream,Writer
2、是纯文本:Writer
3、设备:硬盘File
FileWriter fw = new FileWriter("a.txt");
fw.write("你好");
P.S.
FileWriter是用来写入字符文件的便捷类,此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。
代码:- import java.io.FileWriter;
- import java.io.IOException;
- public class TransStreamDemo {
- public static void main(String[] args) throws IOException {
- writeText();
- }
- public static void writeText() throws IOException {
- FileWriter fw = new FileWriter("c.txt" );
- fw.write( "你好");
- fw.close();
- }
- }
复制代码 运算结果:
任何Java识别的字符数据使用的都是Unicode码表,但是FileWriter写入本地文件使用的是本地编码,也就是GBK码表。
而OutputStreamWriter可使用指定的编码将要写入流中的字符编码成字节。
代码: - import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.OutputStreamWriter;
- public class TransStreamDemo {
- public static void main(String[] args) throws IOException {
- writeText();
- }
- public static void writeText() throws IOException {
- //下面这句代码等同于FileWriter fw = new FileWriter("b.txt");
- //FileWriter其实就是转换流指定了本机默认码表的体现,而且这个转换流的子类对象,可以方便操作文本文件。
- //简单说:操作文件的字节流+本机默认的编码表。
- //这是按照默认码表来操作文件的便捷类
- //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"GBK");
-
- //如果操作文本文件需要明确具体的码表,FileWriter就不行了,必须用转换流。
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt" ),"UTF-8" );
- osw.write( "您好");
- osw.close();
- }
- }
复制代码 运行结果:
P.S.
UTF-8编码,一个中文三个字节。
需求:打印d.txt文件中的内容至控制台显示。
代码:
- import java.io.FileReader;
- import java.io.IOException;
- public class TransStreamDemo {
- public static void main(String[] args) throws IOException {
- readText();
- }
- public static void readText() throws IOException {
- FileReader fr = new FileReader("d.txt" );
- char[] buf = new char[10];
- int len = fr.read(buf);
- String str = new String(buf,0,len);
- System.out.println(str);
- fr.close();
- }
- }
复制代码 运行结果:
原因分析:由于d.txt文件中是UTF-8编码的“您好”,6个字节。
使用FileReader类是用GBK编码进行读取,6个字节代表3个字符,并且按照GBK进行解码,因此才出现如上结果。
需求:打印c.txt文件中的内容至控制台显示。
代码:
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- public class TransStreamDemo {
- public static void main(String[] args) throws IOException {
- writeText();
- }
- public static void writeText() throws IOException {
- InputStreamReader isr = new InputStreamReader(new FileInputStream("c.txt" ),"UTF-8" );
- char[] buf = new char[10];
- int len = isr.read(buf);
- String str = new String(buf,0,len);
- System.out.println(str);
- isr.close();
- }
- }
复制代码 运行结果:
原因分析:由于c.txt文件中是GBK编码的“您好”,4个字节。
使用InputStreamReader类是用UTF-8编码进行读取,由于GBK编码的字节使用UTF-8没有对应的字符,因此使用“?”进行代替。
需求:按照指定编码写字符到指定文件中。
如果需求中已经明确指定了编码表。那就不可以使用FileWriter,因为FileWriter内部使用的默认的本地码表。只能使用其父类,OutputStreamWriter。
OutputStreamWriter接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStream。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName);
并且需要高效:
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
什么时候使用转换流呢?
1、源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁,提高对文本操作的便捷。
2、一旦操作文本涉及到具体的指定编码表时,必须使用转换流。
P.S.
字符流继承体系简图
字节流继承体系简图
8.2.7 File类
File类用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。
P.S.
流只能操作数据,不能操作文件。
示例1:
- import java.io.File;
- public class FileDemo{
- public static void main(String[] args){
- constructorDemo();
- }
- public static void constructorDemo(){
- //可以将一个已存在的,或者不存在的文件或者目录封装成file对象
- //方式一
- File f1 = new File("d:\\demo\\a.txt" );
- //方式二
- File f2 = new File("d:\\demo" ,"a.txt" );
-
- //方式三
- File f = new File("d:\\demo" );
- File f3 = new File(f,"a.txt" );
- //考虑到Windows和Linux系统通用
- File f4 = new File("d:" + File.separator + "demo" + File.separator + "a.txt" );
- }
- }
复制代码 运行结果:
P.S
File.separator是与系统有关的默认名称分隔符。在 UNIX 系统上,此字段的值为 '/';在 Microsoft Windows 系统上,它为 '\\'。
File对象的常用方法:
1、获取
获取文件名称
获取文件路径
获取文件大小
获取文件修改时间
示例2:
- import java.io.File;
- import java.text.DateFormat;
- import java.util.Date;
- public class FileMethodDemo{
- public static void main(String[] args){
- getDemo();
- }
- public static void getDemo(){
- File file1 = new File("a.txt" );
- File file2 = new File("d:\\demo\\a.txt" );
- String name = file2.getName();
- String absPath = file2.getAbsolutePath(); //绝对路径
- String path1 = file1.getPath();
- String path2 = file2.getPath();
- long len = file2.length();
- long time = file2.lastModified();
- //相对路径不同,父目录不同
- //如果此路径名没有指定父目录,则返回 null
- String parent1 = file1.getParent();
- String parent2 = file2.getParent();
-
- Date date = new Date(time);
- DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
- String str_time = df.format(date);
- System.out.println( "name:" + name);
- System.out.println( "absPath:" + absPath);
- System.out.println( "path1:" + path1);
- System.out.println( "path2:" + path2);
- System.out.println( "len:" + len);
- System.out.println( "str_time:" + str_time);
- System.out.println( "parent1:" + parent1);
- System.out.println( "parent2:" + parent2);
- }
- }
复制代码 运行结果:
示例3:
- import java.io.File;
- import java.io.IOException;
- public class FileMethodDemo{
- public static void main(String[] args) throws IOException {
- createAndDeleteDemo();
- }
- public static void createAndDeleteDemo() throws IOException {
- File file = new File("file.txt" );
- //和输出流不一样,如果文件不存在,则创建,如果文件存在,则不创建
- boolean b1 = file.createNewFile();
- System.out.println( "b1 = " + b1);
- //使用delete方法删除文件夹的时候,如果文件夹中有文件,则会删除失败
- boolean b2 = file.delete();
- System.out.println( "b2 = " + b2);
- File dir = new File("abc\\ab" );
- //使用mkdir可以创建多级目录
- boolean b3 = dir.mkdir();//make directory
- System.out.println( "b3 = " + b3);
- //最里层目录被干掉,dir代表的是最里层的目录
- boolean b4 = dir.delete();
- }
- }
复制代码 运行结果:
3、判断
示例4:
- import java.io.File;
- import java.io.IOException;
- public class FileMethodDemo{
- public static void main(String[] args) throws IOException {
- isDemo();
- }
- public static void isDemo() throws IOException {
- File f = new File("aaa.txt" );
-
- boolean b = f.exists();
- System.out.println( "b = " + b);
- if(!f.exists()){
- f.createNewFile();
- }
- //最好先判断是否存在
- if(f.exists()){
- System.out.println(f.isFile());
- System.out.println(f.isDirectory());
- }
- f = new File("aa\\bb" );
- f.mkdirs();
- if(f.exists()){
- System.out.println(f.isFile());
- System.out.println(f.isDirectory());
- }
- }
- }
复制代码 运行结果:
4、重命名
示例5:
- import java.io.File;
- import java.io.IOException;
- public class FileMethodDemo{
- public static void main(String[] args) throws IOException {
- renameToDemo();
- }
- public static void renameToDemo() throws IOException {
- File f1 = new File("d:\\code\\day21\\0.mp3" );
- File f2 = new File("d:\\code\\day21\\1.mp3" );
- boolean b = f1.renameTo(f2);
- System.out.println( "b = " + b);
- }
- }
复制代码 运行结果:
5、系统根目录和容量获取
示例6:
- import java.io.File;
- import java.io.IOException;
- public class FileMethodDemo{
- public static void main(String[] args) throws IOException {
- listRootsDemo();
- }
- public static void listRootsDemo() throws IOException {
- File[] files = File.listRoots();
- for(File file : files){
- System.out.println(file);
- }
- File file = new File("d:\\" );
- System.out.println( "getFreeSpace:" + file.getFreeSpace());
- System.out.println( "getTotalSpace:" + file.getTotalSpace());
- System.out.println( "getUsableSpace:" + file.getUsableSpace());
- }
- }
复制代码 运行结果:
需求:获取目录下的文件以及文件夹的名称。
代码:
- import java.io.File;
- import java.io.IOException;
- public class FileListDemo{
- public static void main(String[] args) throws IOException {
- listDemo();
- }
- public static void listDemo() throws IOException {
- File file = new File("c:\\" );
- //获取目录下的文件以及文件夹的名称,包含隐藏文件
- //调用list方法的File对象中封装的必须是目录,否则会产生NullPointerException
- //如果访问的是系统级目录也会发生空指针异常
- //如果目录存在但是没有内容,会返回一个数组,但是长度为0
- String[] names = file.list();
-
- for(String name : names){
- System.out.println(name);
- }
- }
- }
复制代码 运行结果:
需求:获取d盘demo目录下后缀名为java的文件。
代码:
- import java.io.File;
- import java.io.FilenameFilter;
- public class FileListDemo{
- public static void main(String[] args){
- listDemo();
- }
- public static void listDemo(){
- File dir = new File("d:\\code\\day21" );
-
- String[] names = dir.list( new FilterByJava());
- for(String name : names){
- System.out.println(name);
- }
- }
- }
- class FilterByJava implements FilenameFilter{
- public boolean accept(File dir,String name){
- return name.endsWith(".java" );
- }
- }
复制代码 运行结果:
P.S.
由于搜索后缀为“.java”便直接将“.java”写死到代码中,不便于修改。
如果要求搜索后缀为“.txt”的文件又该怎么办呢?
因此,为了提升程序的通用性,修改后的代码如下:
代码:
- import java.io.File;
- import java.io.FilenameFilter;
- public class FileListDemo{
- public static void main(String[] args){
- listDemo();
- }
- public static void listDemo(){
- File dir = new File("d:\\code\\day21" );
- String[] names = dir.list( new SuffixFilter(".java" ));
- for(String name : names){
- System.out.println(name);
- }
- }
- }
- class SuffixFilter implements FilenameFilter{
- private String suffix;
- public SuffixFilter(String suffix){
- super();
- this.suffix = suffix;
- }
- public boolean accept(File dir, String name) {
- return name.endsWith(suffix);
- }
- }
复制代码 运行结果:
~END~
|