掌握:节点流、缓冲流、转换流、对象流

其余均为了解内容

File类的使用

概念

  • java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关。

  • File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。

  • 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。

  • File对象可以作为参数传递给流的构造器。

  • File类不涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流。

    后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的“终点“

路径分隔符

  • 路径中的每级目录之间用一个路径分隔符隔开。

  • 路径分隔符和系统有关:

    ①windows和DOS系统默认使用“\”来表示

    ②UNIX和URL使用“/”来表示

  • Java程序支持跨平台运行,因此路径分隔符要慎用,为了解决这个隐患,File类提供了一个常量:

    public static final String separator。根据操作系统,动态的提供分隔符。

内存:

常用构造器

  • public File(String pathname):以pathname为路径创建对象(绝对路径或相对路径),相对路径默认当前路径为系统属性user.dir。
    说明:
    IDEA中:
    如果开发使用JUnit中的单元测试方法测试,相对路径即为当前Module下;
    如果使用main()测试,相对路径即为当前的Project下。
    Eclipse中:
    不管是单元测试方法还是main()测试,相对路径都是当前的Project下。
  • public File(String parent,String child):以parent为父路径,child为子路径创建File对象。
  • public File(File parent,String child):根据一个父File对象和子文件路径创建File对象。

常用方法

File类的获取功能:

  1. public String getAbsolutePath():获取绝对路径
  2. public String getPath():获取路径
  3. public String getName() :获取名称
  4. public String getParent():获取上层文件目录路径。若无,返回null
  5. public long length() :获取文件长度(即:字节数)。不能获取目录的长度
  6. public long lastModified() :获取最后一次的修改时间,毫秒值
  7. public String[] list():获取指定目录下的所有文件或者文件目录的名称数组
  8. public File[] listFiles():获取指定目录下的所有文件或者文件目录的File数组

File类的重命名功能:

  • public boolean renameTo(File dest):把文件重命名为指定的文件路径

    比如file1.renameTo(file2),要保证返回true,需要file1在硬盘中存在且file2在硬盘中不存在。修改可包括路径和文件内容。

File类的判断功能:

  1. public boolean isDirectory():判断是否是文件目录
  2. public boolean isFile():判断是否是文件
  3. public boolean exists():判断是否存在
  4. public boolean canRead():判断是否可读
  5. public boolean canWrite():判断是否可写
  6. public boolean isHidden():判断是否隐藏

File类的创建功能:

  1. public boolean createNewFile():创建文件。若文件存在,则不创建,返回false
  2. public boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
  3. public boolean mkdirs():创建文件目录。如果上层文件目录不存在,一并创建
  • 注意事项:如果你创建文件或者文件目录没有写盘符路径,那么默认在项目路径下。

File类的删除功能:

  • public boolean delete():删除文件或者文件夹

  • 删除注意事项:

    ①Java中的删除不走回收站;

    ②要删除一个文件目录,请注意该文件目录内不能包含文件或文件目录。

练习题

  1. 利用File构造器,new 一个文件目录file。

    1)在其中创建多个文件和目录

    2)编写方法,实现删除file中指定文件的操作

  2. 判断指定目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称。

  1. 遍历指定目录所有文件名称,包括子文件目录中的文件。

    拓展1:并计算指定目录占用空间的大小

    拓展2:删除指定文件目录及其下的所有文件

IO流原理及流的分类

Java IO原理

  • I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
  • Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行的。
  • java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
  • 输入输出:进入内存即为输入(Input),出内存即为输出(Output)。

流的分类

  • 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)。
  • 按数据流的流向不同分为:输入流,输出流。
  • 按流的角色的不同分为:节点流,处理流。
(抽象基类) 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer
  • Java的IO流共涉及40多个类,实际上非常规则,都是从者4个类派生的,由这4个类派生出来的子类名称都是以其父类名作为子类名后缀

IO流体系

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
FilterInputStream FilterOutputStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

节点流和处理流

  • 节点流:直接从数据源或目的地读写数据。
  • 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

InputStream & Reader

  • InputStream和Reader是所有输入流的基类。

  • InputStream(典型实现:FileInputStream

    ①int read()

    ②int read(byte[] b)

    ③int read(byte[] b,int off,int len)

  • Reader(典型实现:FileReader

    ①int read()

    ②int read(byte[] b)

    ③int read(byte[] b,int off,int len)

  • 程序中打开的文件IO资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件IO资源。

  • FileInputStream 从文件系统中的某个文件中获得输入字节。FileInputStream用于读取非文本数据之类的原始字节流。要读取字符流,需要使用FileReader。

InputStream

  • int read():从输入流中读取数据的下一个字节。返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值-1。
  • int read(byte[] b):从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取的字节数
  • int read(byte[] b, int off,int len):将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于文件末尾而没有可用的字节,则返回值 -1。
  • public void close() throws IOException:关闭此输入流并释放与该流关联的所有系统资源。

Reader

  • int read():读取单个字符。作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码),如果已到达流的末尾,则返回 -1。
  • int read(char[] cbuf):将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。
  • int read(char[] cbuf,int off,int len):将字符读入数组的某一部分。存到数组cbuf中,从off处开始存储,最多读len个字符。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。
  • public void close() throws IOException:关闭此输入流并释放与该流关联的所有系统资源。

OutputStream & Writer

  • OutputStream 和 Writer 也非常相似:

    ①void write(int b/int c);

    ②void write(byte[] b/char[] cbuf);

    ③void write(byte[] b/char[] buff, int off, int len);

    ④void flush();

    ⑤void close(); 需要先刷新,再关闭此流

  • 因为字符流直接以字符作为操作单位,所以 Writer 可以用字符串来替换字符数组,即以 String 对象作为参数

    ①void write(String str);

    ②void write(String str, int off, int len);

  • FileOutputStream 从文件系统中的某个文件中获得输出字节。FileOutputStream用于写出非文本数据之类的原始字节流。要写出字符流,需要使用 FileWriter。

OutputStream

  • void write(int b):将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入0~255范围的。
  • void write(byte[] b):将 b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定是:应该与调用 write(b, 0, b.length) 的效果完全相同。
  • void write(byte[] b,int off,int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
  • public void flush()throws IOException:刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。
  • public void close() throws IOException:关闭此输出流并释放与该流关联的所有系统资源。

Writer

  • void write(int c):写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。 即写入0 到 65535 之间的Unicode码。
  • 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):写入字符串的某一部分。
  • void flush():刷新该流的缓冲,则立即将它们写入预期目标。
  • public void close() throws IOException:关闭此输出流并释放与该流关联的所有系统资源。

节点流(或文件流)

通用步骤:

  1. 实例化File类对象,指明要操作的文件
  2. 提供具体的流
  3. 数据的操作
  4. 关闭资源

注意:异常处理。

字符流

package top.triabin._02iostream;

import org.junit.Test;

import java.io.*;

/**
*
*
* @author DawnLee
* @create 2020-11-19 10:12
*/
public class FileReaderWriterTest {
/**
* 将Chapter13下的hello.txt文件内容读入程序中,并输出到控制台。
*
* 说明:
* 1.read()的理解:返回读入的一个字符,如果到大文件末尾,返回-1.
* 2.异常处理:为了保证资源一定可以执行关闭操作。需要使用try-catch-finally处理。
* 3.读入文件一定要存在,否则就会报FileNotFoundException
*
*/
@Test
public void test1(){
FileReader fr = null;
try {
//1.实例化File类对象,指明要操作的文件
File file = new File("hello.txt");

//2.提供具体的流
fr = new FileReader(file);

//3.数据的读入
//方式一:
// int data = fr.read();//返回读入的一个字符,如果到达文件末尾,返回-1。
// while(data != -1){
// System.out.print((char) data);
// data = fr.read();
// }

//方式二:语法上针对于方式一的修改
int data;
while((data = fr.read()) != -1){
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭
try {
if(fr != null){
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}
/**
* 对read()操作升级:使用read()的重载方法
*/
@Test
public void testFileReader1(){
FileReader fr = null;
try {
//1.File类的实例化
File file = new File("hello.txt");

//2.FileReader流的实例化
fr = new FileReader(file);

//3.读入操作
//read(char[] cbuf):返回每次读入cbuf数组中的字符的个数,如果到达文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){
//方式一:
//错误的写法
// for (int i = 0; i < cbuf.length; i++) {
// System.out.print(cbuf[i]);//helloworld123ld,最后一次只读入了3个字符,数组中最后两个字符没有被覆盖
// }
//正确写法:
// for (int i = 0; i < len; i++) {
// System.out.print(cbuf[i]);
// }

//方式二:
//对应方式一的错误写法
// String str = new String(cbuf);
// System.out.println(str);
//正确写法:
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null){
//4.资源的关闭
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/**
* 从内存中写出数据到硬盘的文件里
* 说明:
* 1.输出操作,对应的File可以不存在。
* 如果不存在,在输出过程中,会自动创建此文件
* 如果存在:
* 使用的流构造器是: FileWriter(file,false) / FileWriter(file),对原有文件覆盖
* 使用的流构造器是:FileWriter(file,true),不会对原有文件覆盖,而是在原有文件的基础上追加内容
*
*/
@Test
public void testFileWriter() throws IOException {
//1.提供File类的对象,指明写出到的文件
File file = new File("hello1.txt");

//2.提供FileWriter的对象,用于数据写出
FileWriter fw = new FileWriter(file,false);//append:追加

//3.写出操作
fw.write("I have a dream!");
fw.write("\nYou need to have a dream,as well!");


//4.流的关闭
fw.close();
}

@Test
public void testFileReadeFileWriter(){
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File destFile = new File("hello2.txt");

//不能用字符流来处理图片等字节数据
// File srcFile = new File("像玛雅的小姐姐.jpg");
// File destFile = new File("像玛雅的小姐姐1.jpg");//运行成功,但显示图片已损坏

//2.创建输入输出流对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);

//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中字符的个数
while((len = fr.read(cbuf)) != -1){
fw.write(cbuf,0,len);//每次写入读入的len个字符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭资源流
// try {
// if(fw != null)
// fw.close();
// } catch (IOException e) {
// e.printStackTrace();
// }finally{
// try {
// if(fr != null)
// fr.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// 或
try{
if(fw != null){
fw.close();
}
}catch (IOException e){
e.printStackTrace();
}

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

}
}

字节流

package top.triabin._02iostream;

import org.junit.Test;

import java.io.*;

/**
* 测试FileInputStream与OutputStream的使用
*
* 结论:
* 1.对于文本文件,使用字符流处理
* 2.对于非文本文件,使用字节流处理
*
* @author DawnLee
* @create 2020-11-19 11:36
*/
public class FileInputOutputStreamTest {
//使用字节流处理文本文件,可能出现乱码
@Test
public void testInputStream(){
FileInputStream fis = null;
try {
//1.造文件
File file = new File("hello.txt");
//2.造流
fis = new FileInputStream(file);

//3.读数据
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
String str = new String(buffer,0,len);
System.out.print(str);//helloworld123��工���
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
//4.关闭资源
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

//实现对图片的复制
@Test
public void testFileInputOutputStream(){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//1.
File srcFile = new File("像玛雅的小姐姐.jpg");
File destFile = new File("像玛雅的小姐姐1.jpg");

//2.
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);

//3.
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/**
* 实现指定路径下文件的复制操作
*
*/
public void copyFile(String srcPath,String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//1.
File srcFile = new File(srcPath);
File destFile = new File(destPath);

//2.
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);

//3.
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

@Test
public void testCopyFile(){
long start = System.currentTimeMillis();
String srcPath = "E:\\迅雷下载\\余罪\\余罪13.mp4";//大小:818MB
String destPath = "C:\\Users\\26764\\Desktop\\余罪13.mp4";
copyFile(srcPath,destPath);
long end = System.currentTimeMillis();
System.out.println("整个复制操作花费的时间为:" + (end - start));//13031

//可以复制文本文件
}
}

缓冲流

处理流的一种

package top.triabin._04bufferstream;

import org.junit.Test;

import java.io.*;

/**
* 处理流之一:缓冲流使用
* 1.缓冲流:
* BufferedInputStream
* BufferedOutputStream
* BufferedReader
* BufferedWriter
*
* 2.作用:提高流的读取、写入速度
* 提高速度的原因:内部提供了一个缓冲区(flush():刷新缓冲区)
*
* 3.处理流,就是“套接”在已有的流的基础上。
*
* @author DawnLee
* @create 2020-11-19 12:23
*/
public class BufferedTest {
/**
* 实现非文本文件复制
*/
@Test
public void testBufferedStream(){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File("像玛雅的小姐姐.jpg");
File destFile = new File("像玛雅的小姐姐2.jpg");

//2.造流
//2.1 造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//2.2 造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);

//3.复制的细节:读取、写入
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {//4.资源关闭
//4.资源关闭
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//说明:关闭外层流的同时,内层流也会自动关闭,因此内层流的关闭可以省略
// fos.close();
// fis.close();
}

/**
* 实现文件复制的方法:使用Buffered
*/
public void copyFileWithBuffered(String srcPath,String destPath){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File(srcPath);
File destFile = new File(destPath);

//2.造流
//2.1 造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//2.2 造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);

//3.复制的细节:读取、写入
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {//4.资源关闭
//4.资源关闭
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//说明:关闭外层流的同时,内层流也会自动关闭,因此内层流的关闭可以省略
// fos.close();
// fis.close();
}
@Test
public void testCopy(){
long start = System.currentTimeMillis();
String srcPath = "E:\\迅雷下载\\余罪\\余罪13.mp4";//大小:818MB
String destPath = "C:\\Users\\26764\\Desktop\\余罪13.mp4";
copyFileWithBuffered(srcPath,destPath);
long end = System.currentTimeMillis();
System.out.println("整个复制操作花费的时间为:" + (end - start));//7833,使用缓冲流之前为13031
}

/**
* BufferedReader和BufferedWriter实现文本文件的复制
*/
@Test
public void testBufferedReaderWriter(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(new File("F:\\Java\\课件笔记源码资料\\1_课件\\第2部分:Java高级编程\\尚硅谷_宋红康_第13章_IO流\\dbcp.txt")));
bw = new BufferedWriter(new FileWriter(new File("C:\\Users\\26764\\Desktop\\dbcp.txt")));

//方式一:使用char[]数组
// char[] cbuf = new char[1024];
// int len;
// while((len = br.read(cbuf)) != -1){
// bw.write(cbuf,0,len);
// }

//方式二:使用String
String data;
while((data = br.readLine()) != null){
//方法一:需要手动加换行符
// bw.write(data + "\n");//data中部包含换行符
//方法二:newLane()方法加换行符
bw.write(data);
bw.newLine();
}

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

练习题

  1. 图片的加密操作。

    package top.triabin._04bufferstream.exer1;

    import org.junit.Test;

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /**
    * 图片加密
    *
    * @author DawnLee
    * @create 2020-11-19 14:56
    */
    public class PicTest {
    /**
    * 图片的加密操作
    */
    @Test
    public void testEncrypt(){
    FileInputStream fis = null;//文件类可省略,它会自动包装为文件类
    FileOutputStream fos = null;
    try {
    fis = new FileInputStream("像玛雅的小姐姐.jpg");
    fos = new FileOutputStream("加密后的玛雅.jpg");

    byte[] buffer = new byte[20];
    int len;
    while((len = fis.read(buffer)) != -1){
    for (int i = 0; i < len; i++) {
    buffer[i] = (byte) (buffer[i] ^ 5);
    }

    fos.write(buffer,0,len);
    }
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    if(fos != null){
    try {
    fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    if(fis != null){
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }

    /**
    * 图片的解密操作
    */
    @Test
    public void testDecode(){
    FileInputStream fis = null;//文件类可省略,它会自动包装为文件类
    FileOutputStream fos = null;
    try {
    fis = new FileInputStream("加密后的玛雅.jpg");
    fos = new FileOutputStream("解密后的玛雅.jpg");

    byte[] buffer = new byte[20];
    int len;
    while((len = fis.read(buffer)) != -1){
    for (int i = 0; i < len; i++) {
    buffer[i] = (byte) (buffer[i] ^ 5);
    }

    fos.write(buffer,0,len);
    }
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    if (fos != null) {
    try {
    fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    if (fis != null) {
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }
  1. 获取文本上每个字符出现的次数

    提示:遍历文本每一个字符,字符及出现次数保存在Map中,将Map中数据写入文件。

转换流

标准输入、输出流

打印流

数据流

对象流

随机存取文件流

NIO.2中Path、Paths、Files类的使用