文章目录

  • 输入输出流,常见文件操作
    • 01 文件对象
      • 1.1 创建一个文件对象
      • 1.2 文件的常用方法1
      • 1.3 文件的常用方法2
      • 1.4 练习
    • 02 什么是流
      • 2.1 流的理解
      • 2.2 文件输入流
      • 2.3 文件输出流
    • 03 字节流
      • 3.1 ASCII码
      • 3.2 以字节流的形式读取文件内容
      • 3.3 以字节流的形式向文件写入数据
    • 04 关闭流的方式
      • 4.1 在try中关闭
      • 4.2 在finally中关闭
      • 4.3 使用try()的方式
    • 05 字符流
      • 5.1 使用字符流读取文件
      • 5.2 使用字符流写入文件
    • 06 中文问题
      • 6.1 编码的概念
      • 6.2 UNICODE和UTF
      • 6.3 文件的编码方式
      • 6.4 正确读取中文
    • 07 缓存流
      • 7.1 使用缓存流读取数据
      • 7.2 使用缓存流写入数据
      • 7.3 flush
      • 7.4 练习之去除java文件中的注释
    • 08 数据
      • 8.1 字符串直接读写
      • 8.2 练习向文件写入两个数字,并读取
    • 09 对象流
      • 9.1 序列化一个对象
      • 9.2 练习之序列化数组
    • 10 System.in
      • 10.1 System.in
      • 10.2 Scanner读取字符串/整数
      • 10.3 练习-自动创建类
    • 11综合练习
      • 11.1文件复制
      • 11.2文件夹复制
      • 11.3查找文件内容
    • 12 流关系图

输入输出流,常见文件操作

01 文件对象

文件和文件夹都是用File代表。

1.1 创建一个文件对象

使用绝对路径或者相对路径创建File对象。实际上,没有创建文件。
基本语法:File f=new File("路径");

     // 绝对路径File f1 = new File("d:/LOLFolder");System.out.println("f1的绝对路径:" + f1.getAbsolutePath());// 相对路径,相对于工作目录,如果在eclipse中,就是项目目录File f2 = new File("LOL.exe");System.out.println("f2的绝对路径:" + f2.getAbsolutePath());// 把f1作为父目录创建文件对象File f3 = new File(f1, "LOL.exe");System.out.println("f3的绝对路径:" + f3.getAbsolutePath());

1.2 文件的常用方法1

  1. 创建文件对象

    File f=new File("d:/LOLFolder/LOL.exe");
    
  2. 判断文件是否存在,返回boolean值

    f.exists();
    
  3. 判断文件是否是文件夹,返回boolean值

    f.isDirectory();
    
  4. 判断文件是否是文件(非文件夹),返回boolean值

    f.isFile();
    
  5. 获取文件的长度

    f.length();
    
  6. 获取文件最后修改时间

    long time = f.lastModified();
    Date d = new Date(time);
    
  7. 设置文件最后修改时间

    f.setLastModified(0);
    //设为1970.1.1 08:00:00
    
  8. 文件重命名(renameTo方法用于对物理文件名称进行修改,但是并不会修改File对象的name属性。)

 File f2 =new File("d:/LOLFolder/DOTA.exe");f.renameTo(f2);//由LOL.exe改为DOTA.exe

1.3 文件的常用方法2

  1. 创建文件对象

    File f=new File("d:/LOLFolder/skin/garen.ski");
    
  2. 获取当前文件夹下的文件
    f.list();
    //以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)File[] fs=f.listFiles;
    //以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
    
  3. 获取所在文件夹
 f.getParent();//以字符串形式返回获取所在文件夹f.getParentFile();//以文件形式获取所在文件夹
  1. 创建文件夹
 f.mkdir();//创建文件夹,如果父文件夹skin不存在,就创建无效f.mkdirs();//创建文件夹,如果父文件夹skin不存在,就会创建父文件夹f.creatNewFile();//创建一个空文件夹,如果父文件夹skin不存在,就会抛出异常//所以创建一个空文件夹之前,通常都会创建父文件夹f.getParentFile.mkdirs();
  1. 列出所有盘符
 f.listRoots();//列出所有的盘符c: d: e: 等等
  1. 删除文件
 f.delete();//删除文件f.deleteOnExit();//JVM结束时,删除文件,常用于临时文件的删除

1.4 练习

  1. 遍历一个文件夹,并找出最大的和最小(非0)的那个文件;
  2. 遍历一个文件夹下所有文件,并找出最大的和最小(非0)的那个文件;

02 什么是流

什么是流(Stream),流就是一系列的数据。

2.1 流的理解

当不同的介质之间有数据交互的时候,JAVA就使用流来实现。
数据源可以是文件,还可以是数据库,网络甚至是其他的程序。
比如:读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
输入流: InputStream;
输出流:OutputStream。

2.2 文件输入流

如下代码,就建立了一个文件输入流,这个流可以用来把数据从硬盘的文件,读取到JVM(内存)。
目前代码只是建立了流,还没有开始读取。

package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;public class TestStream {public static void main(String[] args) {try {File f = new File("d:/lol.txt");// 创建基于文件的输入流FileInputStream fis = new FileInputStream(f);// 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

2.3 文件输出流

 try {File f=new File("d:/lol.txt");FileOutputStream fos=new FileOutputStream(f);}catch(IOException ioe) {ioe.getStackTrace();}

03 字节流

InputStream字节输入流;
OutputStream字节输出流;
用于以字节的形式读取和写入数据。

3.1 ASCII码

所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。

3.2 以字节流的形式读取文件内容

InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取.

package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;public class TestStream {public static void main(String[] args) {try {//准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66File f =new File("d:/lol.txt");//创建基于文件的输入流FileInputStream fis =new FileInputStream(f);//创建字节数组,其长度就是文件的长度byte[] all =new byte[(int) f.length()];//以字节流的形式读取文件所有内容fis.read(all);for (byte b : all) {//打印出来是65 66System.out.println(b);}//每次使用完流,都应该进行关闭fis.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}  }
}

3.3 以字节流的形式向文件写入数据

OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据。

注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。
但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常

package stream;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class TestStream {public static void main(String[] args) {try {// 准备文件lol2.txt其中的内容是空的File f = new File("d:/lol2.txt");// 准备长度是2的字节数组,用88,89初始化,其对应的字符分别是X,Ybyte data[] = { 88, 89 };// 创建基于文件的输出流FileOutputStream fos = new FileOutputStream(f);// 把数据写入到输出流fos.write(data);// 关闭输出流fos.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

练习之文件和目录不存在时,如何写入文件

package stream;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class TestStream {public static void main(String[] args) {try {File f = new File("d:/xyz/abc/def/lol2.txt");//因为默认情况下,文件系统中不存在 d:\xyz\abc\def,所以输出会失败//首先获取文件所在的目录File dir = f.getParentFile();//如果该目录不存在,则创建该目录if(!dir.exists()){//              dir.mkdir(); //使用mkdir会抛出异常,因为该目录的父目录也不存在dir.mkdirs(); //使用mkdirs则会把不存在的目录都创建好}byte data[] = { 88, 89 };FileOutputStream fos = new FileOutputStream(f);fos.write(data);fos.close();} catch (IOException e) {e.printStackTrace();}}
}

练习之拆分文件

package file;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
/*
*@Author hmg
*@Description
*@Time 2019年11月24日下午3:53:52
*@Version1.0
*/
public class TestFile {public static void main(String[] args) {// TODO Auto-generated method stubtry {File inf =new File("e:/eclipse.exe");FileInputStream fis=new FileInputStream(inf);byte[] all=new byte[(int)inf.length()];fis.read(all);int part=all.length/(100*1024);File[] ouf=new File[part+1];for(int i=0;i<ouf.length;i++) {String str="e:/eclipse.exe"+"-"+i;ouf[i]=new File(str);}for(int i=0;i<=part;i++) {FileOutputStream fos=new FileOutputStream(ouf[i]);if(i==part) {int rest=all.length%(100*1024);fos.write(all, i*100*1024,rest );System.out.printf("输出子文件%s,大小是%d字节%n",ouf[i].getAbsoluteFile(),rest);fos.close();}else {fos.write(all, i*100*1024, 100*1024);System.out.printf("输出子文件%s,大小是%d字节%n",ouf[i].getAbsoluteFile(),100*1024);fos.close();}}fis.close();}catch(IOException e) {e.printStackTrace();}}
}


答案:

package file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;public class TestFile {public static void main(String[] args) {int eachSize = 100 * 1024; // 100kFile srcFile = new File("e:/eclipse.exe");splitFile(srcFile, eachSize);}/*** 拆分的思路,先把源文件的所有内容读取到内存中,然后从内存中挨个分到子文件里* @param srcFile 要拆分的源文件* @param eachSize 按照这个大小,拆分*/private static void splitFile(File srcFile, int eachSize) {if (0 == srcFile.length())throw new RuntimeException("文件长度为0,不可拆分");byte[] fileContent = new byte[(int) srcFile.length()];// 先把文件读取到数组中try {FileInputStream fis = new FileInputStream(srcFile);fis.read(fileContent);fis.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 计算需要被划分成多少份子文件int fileNumber;// 文件是否能被整除得到的子文件个数是不一样的// (假设文件长度是25,每份的大小是5,那么就应该是5个)// (假设文件长度是26,每份的大小是5,那么就应该是6个)if (0 == fileContent.length % eachSize)fileNumber = (int) (fileContent.length / eachSize);elsefileNumber = (int) (fileContent.length / eachSize) + 1;for (int i = 0; i < fileNumber; i++) {String eachFileName = srcFile.getName() + "-" + i;File eachFile = new File(srcFile.getParent(), eachFileName);byte[] eachContent;// 从源文件的内容里,复制部分数据到子文件// 除开最后一个文件,其他文件大小都是100k// 最后一个文件的大小是剩余的if (i != fileNumber - 1) // 不是最后一个eachContent = Arrays.copyOfRange(fileContent, eachSize * i, eachSize * (i + 1));else // 最后一个eachContent = Arrays.copyOfRange(fileContent, eachSize * i, fileContent.length);try {// 写出去FileOutputStream fos = new FileOutputStream(eachFile);fos.write(eachContent);// 记得关闭fos.close();System.out.printf("输出子文件%s,其大小是 %d字节%n", eachFile.getAbsoluteFile(), eachFile.length());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}


练习之合并文件

04 关闭流的方式

所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。

  1. 在try中关闭;
  2. 在finally中关闭;
  3. 使用try()的方式。

4.1 在try中关闭

在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

4.2 在finally中关闭

这是标准的关闭流的方式

  1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
  2. 在finally关闭之前,要先判断该引用是否为空
  3. 关闭的时候,需要再一次进行try catch处理

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~

4.3 使用try()的方式

把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。

 //把流定义在try()里,try,catch或者finally结束的时候,会自动关闭try (FileInputStream fis = new FileInputStream(f)) {byte[] all = new byte[(int) f.length()];fis.read(all);for (byte b : all) {System.out.println(b);}} catch (IOException e) {e.printStackTrace();}

练习-

  1. 把 拆分文件 中关闭流的风格,修改成 finally 方式
  2. 把 合并文件 中关闭流的风格,修改成 try() 方式
package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;public class TestStream {public static void main(String[] args) {int eachSize = 100 * 1024; // 100kFile srcFile = new File("d:/eclipse.exe");
//      splitFile(srcFile, eachSize);}/*** 拆分的思路,先把源文件的所有内容读取到内存中,然后从内存中挨个分到子文件里** @param srcFile*            要拆分的源文件* @param eachSize*            按照这个大小,拆分*/private static void splitFile(File srcFile, int eachSize) {if (0 == srcFile.length())throw new RuntimeException("文件长度为0,不可拆分");byte[] fileContent = new byte[(int) srcFile.length()];// 为了在finally中关闭,需要声明在try外面FileInputStream fis = null;try {fis = new FileInputStream(srcFile);fis.read(fileContent);} catch (IOException e) {e.printStackTrace();} finally {// 在finally中关闭try {if(null!=fis)fis.close();} catch (IOException e) {e.printStackTrace();}}int fileNumber;if (0 == fileContent.length % eachSize)fileNumber = (int) (fileContent.length / eachSize);elsefileNumber = (int) (fileContent.length / eachSize) + 1;for (int i = 0; i < fileNumber; i++) {String eachFileName = srcFile.getName() + "-" + i;File eachFile = new File(srcFile.getParent(), eachFileName);byte[] eachContent;if (i != fileNumber - 1)eachContent = Arrays.copyOfRange(fileContent, eachSize * i, eachSize * (i + 1));elseeachContent = Arrays.copyOfRange(fileContent, eachSize * i, fileContent.length);// 为了在finally中关闭,声明在try外面FileOutputStream fos = null;try {fos = new FileOutputStream(eachFile);fos.write(eachContent);System.out.printf("输出子文件%s,其大小是%,d字节%n", eachFile.getAbsoluteFile(), eachFile.length());} catch (IOException e) {e.printStackTrace();} finally {// finally中关闭try {if(null!=fos)fos.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 合并的思路,就是从eclipse.exe-0开始,读取到一个文件,就开始写出到 eclipse.exe中,直到没有文件可以读** @param folder*            需要合并的文件所处于的目录* @param fileName*            需要合并的文件的名称* @throws FileNotFoundException*/private static void murgeFile(String folder, String fileName) {File destFile = new File(folder, fileName);// 使用try-with-resource的方式自动关闭流try (FileOutputStream fos = new FileOutputStream(destFile);) {int index = 0;while (true) {File eachFile = new File(folder, fileName + "-" + index++);if (!eachFile.exists())break;// 使用try-with-resource的方式自动关闭流try (FileInputStream fis = new FileInputStream(eachFile);) {byte[] eachContent = new byte[(int) eachFile.length()];fis.read(eachContent);fos.write(eachContent);fos.flush();}System.out.printf("把子文件 %s写出到目标文件中%n", eachFile);}} catch (IOException e) {e.printStackTrace();}System.out.printf("最后目标文件的大小:%,d字节", destFile.length());}
}

05 字符流

Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据。

5.1 使用字符流读取文件

FileReader 是Reader子类,以FileReader 为例进行文件读取。

package stream;import java.io.File;
import java.io.FileReader;
import java.io.IOException;public class TestStream {public static void main(String[] args) {// 准备文件lol.txt其中的内容是ABFile f = new File("d:/lol.txt");// 创建基于文件的Readertry (FileReader fr = new FileReader(f)) {// 创建字符数组,其长度就是文件的长度char[] all = new char[(int) f.length()];// 以字符流的形式读取文件所有内容fr.read(all);for (char b : all) {// 打印出来是A BSystem.out.println(b);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

5.2 使用字符流写入文件

FileWriter 是Writer的子类,以FileWriter 为例把字符串写入到文件。

package stream;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;public class TestStream {public static void main(String[] args) {// 准备文件lol2.txtFile f = new File("d:/lol2.txt");// 创建基于文件的Writertry (FileWriter fr = new FileWriter(f)) {// 以字符流的形式把数据写入到文件中String data="abcdefg1234567890";char[] cs = data.toCharArray();fr.write(cs);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

06 中文问题

6.1 编码的概念

计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字。
工作后经常接触的编码方式有如下几种:

  1. ISO-8859-1 ASCII 数字和西欧字母
  2. GBK GB2312 BIG5 中文
  3. UNICODE (统一码,万国码)

其中
ISO-8859-1 包含 ASCII;
GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文;
UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中。

6.2 UNICODE和UTF

UNICODE因为要存放所有的数据,那么它的棋盘是最大的,因此每个字符的字节最长(4字节),占用空间也大。为了给数据“瘦身”,出现了各种减肥子编码——UTF-8,UTF-16和UTF-32。UTF-8是比较常用的方式。
Java采用的是Unicode。写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。

//一个汉字使用不同编码方式的表现
public class TestFile {public static void main(String[] args) {String str="中";showCode(str);}private static void showCode(String str) {String[] encodes = { "BIG5", "GBK", "GB2312", "UTF-8", "UTF-16", "UTF-32" };for(String en:encodes)showCode(str,en);      }private static void showCode(String str,String encodes) {try {System.out.printf("字符:“%s”的编码方式%s下的十六进制是:%n",str,encodes);byte[] bs=str.getBytes(encodes);for(byte b:bs) {int i=b&0xff;System.out.print(Integer.toHexString(i)+"\t");}System.out.println();System.out.println();}catch(UnsupportedEncodingException e) {e.printStackTrace();}}
}

6.3 文件的编码方式

  1. 记事本
    打开任意文本文件,另存为,出现:

    其中:
    ANSI 这个不是ASCII的意思,而是采用本地编码的意思。如果你是中文的操作系统,就会使GBK,如果是英文的就会是ISO-8859-1
    Unicode/UNICODE原生的编码方式
    Unicode big endian 另一个 UNICODE编码方式
    UTF-8 最常见的UTF-8编码方式,数字和字母用一个字节, 汉字用3个字节。
  2. eclipse
    eclipse也有类似记事本的编码方式,右键任意文本文件,点击最下面的"property",就可以看到Text file encoding。

6.4 正确读取中文

  1. 用FileInputStream

(1)必须了解文本是以哪种编码方式保存字符的;
(2)使用字节流读取了文本后,再使用对应的编码方式去识别这些数字,得到正确的字符。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;public class TestStream {public static void main(String[] args) {File f = new File("E:\\project\\j2se\\src\\test.txt");try (FileInputStream fis = new FileInputStream(f);) {byte[] all = new byte[(int) f.length()];fis.read(all);//文件中读出来的数据是System.out.println("文件中读出来的数据是:");for (byte b : all){int i = b&0x000000ff;  //只取16进制的后两位System.out.println(Integer.toHexString(i));}System.out.println("把这个数字,放在GBK的棋盘上去:");String str = new String(all,"GBK");System.out.println(str);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
  1. 用FIleReader

FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:
new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"));
在本例中,用记事本另存为UTF-8格式,然后用UTF-8就能识别对应的中文了。
解释: 为什么中字前面有一个?
如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做BOM用来标志这个文件是用UTF-8来编码的。

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.io.File;
public class TestFile {public static void main(String[] args) {File f=new File("e:/lol.txt");try(FileReader fr=new FileReader(f);InputStreamReader isr=new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"));){System.out.println("默认编码是:"+Charset.defaultCharset());char []ch=new char[(int)f.length()];fr.read(ch);System.out.printf("FileReader会使用默认的编码方式GBK,识别出来的字符是:%n%s%n%n",new String(ch));ch=new char[(int)f.length()];isr.read(ch);System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n%s%n",new String(ch));}catch(IOException e) {e.printStackTrace();}}
}

//找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字
import java.io.UnsupportedEncodingException;
public class TestFile {public static void main(String[] args) throws UnsupportedEncodingException {byte[] bs=new byte[3];bs[0]=(byte)0xE5;bs[1]=(byte)0xB1;bs[2]=(byte)0x8C;String str=new String(bs,"UTF-8");System.out.println(str);       }
}

07 缓存流

缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。
就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲。

7.1 使用缓存流读取数据

缓存字符输入流 BufferedReader 可以一次读取一行数据。

package stream;import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;public class TestStream {public static void main(String[] args) {// 准备文件lol.txt其中的内容是// garen kill teemo// teemo revive after 1 minutes// teemo try to garen, but killed againFile f = new File("d:/lol.txt");// 创建文件字符流// 缓存流必须建立在一个存在的流的基础上try (FileReader fr = new FileReader(f);BufferedReader br = new BufferedReader(fr);){while (true) {// 一次读一行String line = br.readLine();if (null == line)break;System.out.println(line);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

7.2 使用缓存流写入数据

PrintWriter 缓存字符输出流, 可以一次写出一行数据。

package stream;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;public class TestStream {public static void main(String[] args) {// 向文件lol2.txt中写入三行语句File f = new File("d:/lol2.txt");try (// 创建文件字符流FileWriter fw = new FileWriter(f);// 缓存流必须建立在一个存在的流的基础上              PrintWriter pw = new PrintWriter(fw);              ) {pw.println("garen kill teemo");pw.println("teemo revive after 1 minutes");pw.println("teemo try to garen, but killed again");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

7.3 flush

有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush。

package stream;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {public static void main(String[] args) {//向文件lol2.txt中写入三行语句File f =new File("d:/lol2.txt");//创建文件字符流//缓存流必须建立在一个存在的流的基础上try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {pw.println("garen kill teemo");//强制把缓存中的数据写入硬盘,无论缓存是否已满pw.flush();           pw.println("teemo revive after 1 minutes");pw.flush();pw.println("teemo try to garen, but killed again");pw.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

7.4 练习之去除java文件中的注释

注意点:要在通过BuffedReader 读取完数据后,才能建立Printwriter,因为创建输出流的时候,会把目标文件内容清空。

import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;public class TestFile {public static void main(String[] args) {File f=new File("e:/LOLFloder/LOL.txt");removeComments(f);}public static void removeComments(File javaFile) {StringBuffer sb=new StringBuffer();System.out.println("去除注释之前:");try(FileReader fr=new FileReader(javaFile);BufferedReader br=new BufferedReader(fr);){while(true) {String str=br.readLine();if(str==null) {break;}System.out.println(str);if(!str.trim().startsWith("//")) {sb.append(str).append("\r\n");}}}catch(IOException e) {e.printStackTrace();}try(FileWriter fw=new FileWriter(javaFile);PrintWriter pw=new PrintWriter(fw)){pw.write(sb.toString());//或者pw.println(sb);}catch(IOException e) {e.printStackTrace();}System.out.println("去除注释之后:");try(FileReader fr=new FileReader(javaFile);BufferedReader br=new BufferedReader(fr);){while(true) {String str=br.readLine();if(str==null) {break;}System.out.println(str);}}catch(IOException e) {e.printStackTrace();}}
}

08 数据

DataInputStream 数据输入流;
DataOutputStream 数据输出流。

8.1 字符串直接读写

使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写。(有顺序)
如本例,通过DataOutputStream 向文件顺序写出布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。

: 要用 DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。

package file;
import java.io.File;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class TestFile {public static void main(String[] args) {write();read();}public static void write() {File f=new File("e:/lol.txt");try(FileOutputStream fos=new FileOutputStream(f);DataOutputStream dos=new DataOutputStream(fos);){dos.writeBoolean(true);dos.writeInt(300);dos.writeUTF("我爱你,I Love You!");}catch(IOException e) {e.printStackTrace();}}public static void read() {File f=new File("e:/lol.txt");try(FileInputStream fis=new FileInputStream(f);DataInputStream dis=new DataInputStream(fis);){boolean b=dis.readBoolean();int i=dis.readInt();String str=dis.readUTF();System.out.printf("%s%d年,是%s的",str,i,b);}catch(IOException e) {e.printStackTrace();}}
}

8.2 练习向文件写入两个数字,并读取

方法1:(使用数据流DataOutputStream向文件连续写入两个数字,然后用DataInpuStream连续读取两个数字)

package file;
import java.io.File;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class TestFile {public static void main(String[] args) {write();read();}public static void write() {File f=new File("e:/lol.txt");try(FileOutputStream fos=new FileOutputStream(f);DataOutputStream dos=new DataOutputStream(fos);){dos.writeInt(300);dos.writeInt(1000);}catch(IOException e) {e.printStackTrace();}}public static void read() {File f=new File("e:/lol.txt");try(FileInputStream fis=new FileInputStream(f);DataInputStream dis=new DataInputStream(fis);){int i=dis.readInt();int j=dis.readInt();System.out.println(i+j);//输出1300}catch(IOException e) {e.printStackTrace();}}
}

方法2:

package file;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;public class TestFile {public static void main(String[] args) {File f=new File("e:/lol.txt");int i=300;String bj="@";int j=1000;try(FileWriter fw=new FileWriter(f);PrintWriter pw=new PrintWriter(fw);){pw.print(i);pw.print(bj);pw.print(j);}catch(IOException e) {e.printStackTrace();}try(FileReader fr=new FileReader(f);BufferedReader br=new BufferedReader(fr);){String s=br.readLine();String[] str=s.split("@");for(String st:str)System.out.println(st);}catch(IOException e) {e.printStackTrace();}    }
}

09 对象流

对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘。
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口。

9.1 序列化一个对象

  1. 创建一个Hero对象,设置其名称为garen。
  2. 把该对象序列化到一个文件garen.lol。
  3. 然后再通过序列化把该文件转换为一个Hero对象

注:把一个对象序列化有一个前提是:这个对象的类,必须实现了Serializable接口。

package charactor;
import java.io.Serializable;
public class Hero implements Serializable {//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号private static final long serialVersionUID = 1L;public String name;public float hp;
}package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;import charactor.Hero;public class TestStream {  public static void main(String[] args) {//创建一个Hero garen//要把Hero对象直接保存在文件上,务必让Hero类实现Serializable接口Hero h = new Hero();h.name = "garen";h.hp = 616;//准备一个文件用于保存该对象File f =new File("d:/garen.lol");try(//创建对象输出流FileOutputStream fos = new FileOutputStream(f);ObjectOutputStream oos =new ObjectOutputStream(fos);//创建对象输入流              FileInputStream fis = new FileInputStream(f);ObjectInputStream ois =new ObjectInputStream(fis);) {oos.writeObject(h);Hero h2 = (Hero) ois.readObject();System.out.println(h2.name);System.out.println(h2.hp);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

9.2 练习之序列化数组

  1. 准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组
  2. 然后把该数组序列化到一个文件heros.lol
  3. 接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样。
    有:
package stream;import java.io.Serializable;public class Hero implements Serializable {//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号private static final long serialVersionUID = 1L;public String name;public float hp;public Hero(String str) {this.name=str;}
}
package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;import charactor.Hero;public class TestStream {public static void main(String[] args) {//创建Hero数组Hero hs[] =new Hero[10];for (int i = 0; i < hs.length; i++) {hs[i] = new Hero("hero:" +i);}File f =new File("d:/heros.lol");try(FileOutputStream fos = new FileOutputStream(f);ObjectOutputStream oos =new ObjectOutputStream(fos);FileInputStream fis = new FileInputStream(f);ObjectInputStream ois =new ObjectInputStream(fis);) {//把数组序列化到文件heros.loloos.writeObject(hs);Hero[] hs2 = (Hero[]) ois.readObject();System.out.println("查看中文件中反序列化出来的数组中的每一个元素:");for (Hero hero : hs2) {System.out.println(hero.name);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

10 System.in

System.out 是常用的在控制台输出数据的;
System.in 可以从控制台输入数据。

10.1 System.in

package stream;import java.io.IOException;
import java.io.InputStream;public class TestStream {public static void main(String[] args) {// 控制台输入try (InputStream is = System.in;) {while (true) {// 敲入a,然后敲回车可以看到// 97 13 10// 97是a的ASCII码// 13 10分别对应回车换行int i = is.read();System.out.println(i);}} catch (IOException e) {e.printStackTrace();}}
}

10.2 Scanner读取字符串/整数

使用System.in.read虽然可以读取数据,但是很不方便;
使用Scanner就可以逐行读取了。

import java.util.Scanner;Scanner s = new Scanner(System.in);while(true){String line = s.nextLine();System.out.println(line);}//String str=s.nextLine();//int i=s.nextInt();//System.out.println(str+i);

10.3 练习-自动创建类

自动创建有一个属性的类文件。
通过控制台,获取类名,属性名称,属性类型,根据一个模板文件,自动创建这个类文件,并且为属性提供setter和getter。
模板文件:

public class @class@ {public @type@ @property@;public @class@() {}public void set@Uproperty@(@type@  @property@){this.@property@ = @property@;}public @type@  get@Uproperty@(){return this.@property@;}
}
package stream;import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;public class TestStream {public static void main(String[] args) {// 接受客户输入Scanner s = new Scanner(System.in);System.out.println("请输入类的名称:");String className = s.nextLine();System.out.println("请输入属性的类型:");String type = s.nextLine();System.out.println("请输入属性的名称:");String property = s.nextLine();String Uproperty = toUpperFirstLetter(property);// 读取模版文件File modelFile = new File("E:\\project\\j2se\\src\\Model.txt");String modelContent = null;try (FileReader fr = new FileReader(modelFile)) {char cs[] = new char[(int) modelFile.length()];fr.read(cs);modelContent = new String(cs);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}      //替换String fileContent = modelContent.replaceAll("@class@", className);fileContent = fileContent.replaceAll("@type@", type);fileContent = fileContent.replaceAll("@property@", property);fileContent = fileContent.replaceAll("@Uproperty@", Uproperty);String fileName = className+".java";//替换后的内容System.out.println("替换后的内容:");System.out.println(fileContent);File file = new File("E:\\project\\j2se\\src",fileName);try(FileWriter fw =new FileWriter(file);){fw.write(fileContent);} catch (IOException e) {e.printStackTrace();}System.out.println("文件保存在:" + file.getAbsolutePath());}public static String toUpperFirstLetter(String str){char upperCaseFirst =Character.toUpperCase(str.charAt(0));String rest = str.substring(1);return upperCaseFirst + rest;}
}

11综合练习

11.1文件复制

复制文件是常见的IO操作,设计如下方法,实现复制源文件srcFile到目标文件destFile。
需要留意的是,read会返回实际的读取数量,有可能实际的读取数量小于缓冲的大小,那么把缓冲中的数据写出到目标文件的时候,就只应该写出部分数据。

package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class TestStream {public static void main(String[] args) {String srcFile="e:/lol.txt";String destFile="e:/lol2.txt";copyFile( srcFile, destFile);}public static void copyFile(String srcFile, String destFile){File src=new File(srcFile);File dest=new File(destFile);//缓存区,一次性读取1024字节byte[] buffer=new byte[1024];try(FileInputStream fis=new FileInputStream(src);FileOutputStream fos=new FileOutputStream(dest);) {while(true) {实际读取的长度是 actuallyReaded,有可能小于1024int actuallyReaded = fis.read(buffer);//-1表示没有可读的内容了if(-1==actuallyReaded)break;fos.write(buffer,0,actuallyReaded);fos.flush();}}catch(IOException e) {e.printStackTrace();}}
}

11.2文件夹复制

复制文件夹,实现如下方法,把源文件夹下所有的文件 复制到目标文件夹下(包括子文件夹)

package stream;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;//需求:复制文件夹
//需提前准备好源文件"e:/cola",和空的目标文件夹"e:/cola-副本"
public class TestStream {public static void main(String[] args) {String srcFolder="e:/cola";String destFolder="e:/cola-副本";copyFolder( srcFolder, destFolder);}public static void copyFolder(String srcFolder, String destFolder){File src=new File(srcFolder);File dest = new File(destFolder);//源文件夹不存在if(!src.exists())return;//源文件夹不是一个文件夹if(!src.isDirectory())return;//目标文件夹是一个文件if(dest.isFile())return;File[] fs=src.listFiles();for(File f:fs) {if(f.isFile()) {String srcFilePath=f.getPath();String destFilePath=destFolder+"/"+f.getName()+"-副本";copyFile(srcFilePath,destFilePath);}if(f.isDirectory()) {String srcFilePath=f.getPath();String destFilePath=destFolder+"/"+f.getName()+"-副本";File newdest=new File(destFilePath);newdest.mkdirs();//创建新文件夹copyFolder(srcFilePath, destFilePath);}}}public static void copyFile(String srcFile, String destFile){File src=new File(srcFile);File dest=new File(destFile);//缓存区,一次性读取1024字节byte[] buffer=new byte[1024];try(FileInputStream fis=new FileInputStream(src);FileOutputStream fos=new FileOutputStream(dest);) {while(true) {实际读取的长度是 actuallyReaded,有可能小于1024int actuallyReaded = fis.read(buffer);//-1表示没有可读的内容了if(-1==actuallyReaded)break;fos.write(buffer,0,actuallyReaded);fos.flush();}}catch(IOException e) {e.printStackTrace();}}
}

11.3查找文件内容

假设你的项目目录是E:\eclipse-jee-2019-06-R-win32-x86_64\work,遍历这个目录下所有的java文件(包括子文件夹),找出文件内容包括 Magic的那些文件,并打印出来。

public static void main(String[] args) {File folder=new File("E:\\eclipse-jee-2019-06-R-win32-x86_64\\work");String search="magic";search(folder,search);}public static void search(File folder, String search) {if(isJavaFile(folder)) {try(FileReader fis=new FileReader(folder);) {char[] cs=new char[(int)folder.length()];fis.read(cs);String folderStr=new String(cs);if(folderStr.contains(search)) {System.out.printf("找到子目标字符串%s,在文件:%s%n",search,folder.getAbsoluteFile());}}catch(IOException e) {e.printStackTrace();}}if(folder.isDirectory()) {File[] files=folder.listFiles();for(File fs:files) {search(fs,search);}} }

12 流关系图

这个图把本章节学到的流关系做了个简单整理

  1. 流分为字节流和字符流
  2. 字节流下面常用的又有数据流和对象流
  3. 字符流下面常用的又有缓存流

本文学习内容均来自how2j.cn,用于个人笔记和总结,想学习的可以到该网站学习哦,侵删。

JAVA中级二 输入输出流,常见文件操作相关推荐

  1. java输入输出及文件_java输入输出流及文件操作

    我只选择了一些代码 注意包声明和相关结构 许多类都继承了MyFile这个类 深入研究可以参考<java文件操作> 1.[代码]读取文件内容 /** *Author:Yuanhonglong ...

  2. Java输入输出流和文件操作

    操作系统中的文件和目录概念 文件与文件系统 文件是信息的一种组织形式,是存储在外部存储介质上的具有标志名的一组相关信息集合. 文件系统用文件概念来组织和管理存放在各种介质上的信息.文件系统提供目录机制 ...

  3. java 1kb_[代码全屏查看]-java输入输出流及文件操作

    [文件] List_File_Dir.java ~ 1KB    下载(14) /** *Author:Yuanhonglong *Date:2013-12-15 *1948281915 */ pac ...

  4. java 对象读写_java 对象输入输出流读写文件的操作实例

    java 对象输入输出流读写文件的操作实例 java 支持对对象的读写操作,所操作的对象必须实现Serializable接口. 实例代码: package vo; import java.io.Ser ...

  5. java用输入流创建数据文件_java开发知识IO知识之输入输出流以及文件

    java开发知识IO知识之输入输出流以及文件 一丶流概述 流十一组有序的数据序列.根据操作的类型,可以分为输入流跟输出流两种. IO(input/output)输入/输出流提供了一条通道程序.可以使用 ...

  6. Java基础知识每日总结(19)---Java输入输出流、文件、递归

    输入输出流.文件.递归 在变量.数组和对象中存储数据是暂时的,程序结束后它们则会丢失.为了能够永久地保存程序创建的数据,需要将其保存在磁盘文件中.这样以后就可以在其他程序中使用它们.Java的I/O技 ...

  7. c语言 文件流 输出数据类型,总结C++中输入输出流及文件流操作

    当程序员在编写程序的时候,最不可分割的是对文件做的相应的操作,总结C++中输入输出流及文件流操作大家都了解吗?想要了解的朋友,就随爱站技术频道小编来看看吧. 1.流的控制 iomanip        ...

  8. 利用输入输出流及文件类编写一个程序,可以实现在屏幕显示文本文件的功能,类似DOS命令中的type命令

    利用输入输出流及文件类编写一个程序,可以实现在屏幕显示文本文件的功能,类似DOS命令中的type命令 package p1;import java.io.BufferedReader; import ...

  9. python中os模块详解_Python OS模块(常见文件操作示例)

    1 Python 常见文件操作示例 2. 3. os.path 模块中的路径名访问函数 4. 分隔 5. basename() 去掉目录路径 , 返回文件名 6. dirname() 去掉文件名 , ...

最新文章

  1. 【全文】Libra回应质疑:Facebook将放弃控制权,不与主权货币竞争
  2. SQLite学习手册(索引和数据分析/清理)
  3. iOS手势操作简介(三)
  4. 用vb.net实现拖放功能
  5. c语言中结构体头文件是什么,函数形参里有结构体指针,为什么在头文件生
  6. 2018级C语言大作业 - 祖玛
  7. 博一结束后的一些反思 -- 该如何平衡科研与生活
  8. 智能硬件无线通信协议的那些事儿(一)
  9. Java 实习生(月薪 3k-5k 水平)应具备哪些知识、能力?给学弟学妹们支招
  10. 永中java的窗口_永中國際 Office
  11. 剑指offer-二叉树中值等于某个数的路径
  12. Unity手机震动,Unity -> ios 震动
  13. 照明工程需要什么资质
  14. Mac打开网页速度奇慢/无法打开内网网页解决方案
  15. MCU在可穿戴计算机生物特征识别中的关键作用
  16. python 多元线性回归的系数检验 t p值_多元线性回归检验t检验(P值),F检验,R方等参数的含义...
  17. 【微信小程序学习】解决多个视频同时播放的问题
  18. 杂论——wly_sh调查笔记
  19. HTTP劫持和DNS劫持
  20. 语音芯片各个管脚的作用你都知道多少?WT588F语音ic

热门文章

  1. element日历(Calendar)排班
  2. 使用h5制作一个五子棋游戏
  3. java五子棋网络版源码_网络版五子棋的java源代码.pdf
  4. CornerNet论文详解CornerNet: Detecting Objects as Paired Keypoints
  5. Zerg虫族的传说[官方资料]
  6. 视频测试软件+视频测试硬件=视频质量测试解决方法+视频测试的重要性
  7. 前端怎么画三角形_css如何画三角形?
  8. 区块链技术在物联网中的应用概述
  9. does not specify a Swift version and none of the targets (`packager`) integrating it have the `SWIFT
  10. 理财项目中宏涌晟五个投资理财基础知识