IO
IO
一、File
类
File
类被定义为文件和目录路径名的抽象表示形式,这是因为File
类既可以表示文件也可以表示目录,他们都通过对应的路径来描述。通过构造函数创建一个
File
类对象,则该对象就是指定文件的引用,可以通过该对象对文件操作。
//创建一个File类对象f,可通过f对temp.txt进行操作
File f = new File("D:\\temp.txt");
路径分隔符:
- Windows下路径分隔符使用反斜线
\
,而Java程序中的反斜线表示转义字符,如果需要在Windows路径下使用反斜线,则应使用两条反斜线,如:C:\\mytest.txt
- 使用斜线
/
,Java程序支持将斜线当成平台无关的路径分隔符。
File
类常见方法:
boolean isHidden()
:判断是否是隐藏文件boolean canRead()
:是否可读boolean canWrite()
:是否可写String getAbsolutePath()
:获取文件的绝对路径String getName()
:获取文件名boolean isDirectory()
:是否是目录boolean isFile()
:是否是文件boolean mkdir()
:创建目录long lastModified()
:最后修改时间long length()
:文件长度File[] listFiles()
:返回目录下的所有文件和目录
public class MyTest1 {
/*
* I---input
* O---output
* IO--输入输出(键盘 显示器 硬盘 网络)
* |---File类---文件和目录(文件夹)的抽象表示形式---File类将文件当成一个整体,不能对文件的内容进行操作,如果对文件的内容操作,需要使用IO流
* 通过File类的对象和文件或目录建立关联,操作File类的对象,就是操作相应的文件或者目录
*
* |---IO流
* */
public static void main(String[] args) {
//创建File类的对象 java.io....
/*
* 文件的路径有两种写法
* C:\\Users\\Raymond\\Desktop\\test\\a.txt
* C:/Users/Raymond/Desktop/test/a.txt
*
* \ 转义字符----和其后的第一个字符结合,表示特殊的含义 \n \t
* 如果要表示\,必须写两条\
*
* */
//File f = new File("C:\\Users\\Maxwell\\Desktop\\a.txt");
File f = new File("C:/Users/Maxwell/Desktop/a.txt");
//File类中常见的方法
//判断文件是否是隐藏文件
System.out.println("是否隐藏:" + f.isHidden());
//大小 Byte
System.out.println("文件的大小:" + f.length());
//文件名
System.out.println("文件名:" + f.getName());
//绝对路径
System.out.println("绝对路径:" + f.getAbsolutePath());
//是否可读
System.out.println("是否可读:" + f.canRead());
//是否可写
System.out.println("是否可写:" + f.canWrite());
/*
* 时间戳---->表示时间的字符串(xxxx年xx月xx日 xx:xx:xx)
*
* SimpleDateFormat
* |
* Date()
* |
* 时间戳
* 时间戳---->Date()
* */
//文件最后修改时间
long lastMdate = f.lastModified();
Date date = new Date(lastMdate);
//Date---String
SimpleDateFormat sft = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String dateStr = sft.format(date);
System.out.println("最后修改时间:" + dateStr);
//判断是否是文件夹
System.out.println("是否是文件夹:" + f.isDirectory());
File f1 = new File("C:/Users/Maxwell/Desktop/test123/");
//判断文件或文件夹是否存在
//System.out.println("是否存在:" + f1.exists());
if(!f1.exists()) { //不存在创建该文件夹
//创建文件夹 Linux mkdir
f1.mkdir();
}
File[] fArr = f1.listFiles();
for (File file : fArr) {
System.out.println(file.getName());
}
}
}
File类中没有提供对文件的读写操作,如果要实现对文件的读写,需要通过IO流来进行操作。
案例:列出一个目录下所有的文件和目录(包括子目录中的目录和文件)
public class MyTest2 {
/*
* f表示需要被遍历的文件夹
* */
public static void listFiles(File f) {
File[] farr = f.listFiles();
for(File subf : farr) {
System.out.println(subf.getAbsolutePath());
if(subf.isDirectory()) {
listFiles(subf);
}
}
}
public static void main(String[] args) {
File file = new File("C:/Users/Maxwell/Desktop/test123/");
listFiles(file);
}
}
二、IO
流概述
2.1、什么是IO
流
I/O
是Input/Output
的缩写,I/O
技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
IO流
是一组有序的,有起点和终点的数据集合,是对数据传输的总称和抽象。
IO作用
:
- 人机交互
- 文件数据读取写入,数据持久化保存
IO
流的源和目的地:
- 内存
- 控制台
- 磁盘文件
- 网络端点
关于
Input
和Output
:
Input
读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中;Output
将程序(内存)数据输出到磁盘、光盘等存储设备中。
2.2、IO
流分类
按照处理的数据单元不同:
- 字节流:操作的数据单元是8位字节,
InputStream
、OutputStream
。二进制文件(声音、图片、视频)、文本文件;- 字符流:操作的数据单元是16位字符,
Reader
、Writer
,通常用于处理文本文件。按照数据流流向不同:
- 输入流:只能从中读取数据,而不能向其写入数据。
InputStream
、Reader
;- 输出流:只能向其写入数据,而不能从中读取数据。
OutputStream
、Writer
;- 输入、输出都是从内存的角度进行划分,内存-->硬盘,输出流;硬盘-->内存,输入流。
字节流 字符流 输入流 InputStream
Reader
输出流 OutputStream
Writer
Java的
IO
流共涉及40多个类,实际上非常规则,都是从上面4个抽象基类派生的。由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
2.3、IO
流处理流程
- 打开流
- 在流中数据传输(输入/输出 读/写)
- 关闭流
程序中打开的文件
IO
资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件IO
资源。
三、字节流
操作的数据单元是8位字节,主要涉及两个抽象类:
InputStream
、OutputStream
。
3.1、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()
:关闭此输入流并释放与该流关联的所有系统资源。
import java.io.FileInputStream;
import java.io.IOException;
public class MyTest3 {
/*
* IO流
*
* 操作步骤:
* 1.打开流
* 2.读/写
* 3.关闭流
* 分类------->能够解决什么情况下选择什么样的IO流的问题
* |---处理数据单元的不同
* |---字节流(8) InputStream OutputStream
* |---字符流 (16) Reader Writer
* |---流向---方向 物理 参考系---内存
* |---输入流 InputStream Reader
* |---输出流 OutputStream Writer
* 1.InputStream OutputStream Reader Writer都是抽象类,我们学习的是他们的子类;
* 2.任何一个IO流同时属于上面两个分类体系;
* 3.处理的内容是二进制文件(声音,图片,视频)使用字节流进行处理
* 4.处理的内容是文本文件(txt)使用字符流进行处理
* */
public static void main(String[] args) throws IOException {
/*
* 使用字节流读取文件并在控制台打印--InputStream--FileInputStream
* */
//打开流
FileInputStream in = new FileInputStream("C:\\Users\\Maxwell\\Desktop\\a.txt");
/*
* 读取文件中的内容
* 1.为了提升读取效率,要一次尽可能读取多个字节的数据----读到数组里面
* 2.文件有可能特别大,数组如果设置特别大会导致程序崩溃----数组的大小不能特别大,不能和被读取的文件一样大,数组要小一点----多次调用读取的方法进行读取----循环读取
* 3.read方法返回-1表示读到文件末尾
*
* read(byte[] arr)
* read(byte[] arr, int off, int len); ***
*/
byte[] arr = new byte[1024];//1KB
int len = 0;
while((len = in.read(arr, 0, 1024)) != -1) {
//内容在数组中----String
//byte[]----String
/*
* 根据数组中的有效信息转换成字符串
* */
String str = new String(arr, 0, len);
//打印转换的内容
System.out.print(str);
}
//关闭流
in.close();
}
}
3.2、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
个字节写入此输出流;void flush()
:刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标;void close()
:关闭此输出流并释放与该流关联的所有系统资源。
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
public class MyTest4 {
public static void main(String[] args) throws IOException {
/*
* 从控制台获取输入,将输入的内容写入到文件当中(使用字节流)
* OutputStream
* */
Scanner sc = new Scanner(System.in);
/*
* 日志文件
*
* */
//打开流
FileOutputStream out = new FileOutputStream("C:\\Users\\Maxwell\\Desktop\\a.txt");
//读取键盘数据
String str = sc.next();
str += "\r\n";
//String--->byte[]
byte[] arr = str.getBytes();
//写入数据
out.write(arr);
//关闭流
out.close();
}
}
在写入一个文件时,如果使用构造器
FileOutputStream(file)
,则目录下有同名文件将被覆盖。如果使用构造器
FileOutputStream(file,true)
,则目录下的同名文件不会被覆盖,在文件内容末尾追加内容。
3.3、字节流实现文件拷贝
public class MyTest5 {
public static void main(String[] args) throws IOException {
//拷贝操作---复制---读取一个文件的内容,写入另外的一个文件
//打开流
FileInputStream in = new FileInputStream("C:\\Users\\Maxwell\\Desktop\\pic.jpg");
FileOutputStream out = new FileOutputStream("C:\\Users\\Maxwell\\Desktop\\pic1.jpg");
byte[] arr = new byte[1024];
int len = 0;
//读写操作
while((len = in.read(arr, 0, 1024)) != -1) {
//读取多少内容,就写入多少内容
out.write(arr, 0, len);
}
//关闭
out.close();
in.close();
}
}
四、字符流
操作的数据单元是16位字符,主要涉及两个抽象类:
Reader
、Writer
,通常用于处理文本文件。
4.1、Reader
主要方法:
int read()
:读取单个字符。作为整数读取的字符,范围在0到65535之间 (2个字节的Unicode码),如果已到达流的末尾,则返回 -1;int read(char[] cbuf)
:将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数;int read(char[] cbuf,int off,int len)
:将字符读入数组的某一部分,存到数组cbuf
中,从off
处开始存储,最多读len
个字符。如果已到达流的末尾,则返回 -1,否则返回本次读取的字符数;close()
:关闭此输入流并释放与该流关联的所有系统资源。
import java.io.FileReader;
import java.io.IOException;
public class MyTest6 {
public static void main(String[] args) throws IOException {
/*
* 字符流(16)---Reader Writer
* */
//打开流
FileReader in = new FileReader("C:\\Users\\Maxwell\\Desktop\\a.txt");
char[] arr = new char[1024];
int len = 0;
//读取
while((len = in.read(arr, 0, 1024)) != -1) {
//打印String
//char[]---->String
String str = new String(arr, 0, len);
System.out.println(str);
}
//关闭
in.close();
}
}
4.2、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()
:刷新该流的缓冲,则立即将它们写入预期目标;void close()
:关闭此输出流并释放与该流关联的所有系统资源。
import java.io.FileWriter;
import java.io.IOException;
public class MyTest7 {
public static void main(String[] args) throws IOException {
//在文件中写入数据---Writer
FileWriter out = new FileWriter("C:\\Users\\Maxwell\\Desktop\\a.txt");
//写入
String str = "abcdefg....";
out.write(str);
//关闭
out.close();
}
}
在写入一个文件时,如果使用构造器
FileWriter(file)
,则目录下有同名文件将被覆盖。如果使用构造器
FileWriter(file,true)
,则目录下的同名文件不会被覆盖,在文件内容末尾追加内容。
4.3、字符流实现文件拷贝
public class MyTest8 {
public static void main(String[] args) throws IOException {
//使用字符流进行文件的拷贝
//打开流
FileReader in = new FileReader("C:\\Users\\Maxwell\\Desktop\\a.txt");
FileWriter out = new FileWriter("C:\\Users\\Maxwell\\Desktop\\b.txt");
char[] arr = new char[1024];
int len = 0;
//读写
while((len = in.read(arr, 0, 1024)) != -1) {
out.write(arr, 0, len);
}
//关闭
out.close();
in.close();
}
}
五、缓冲流
为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,默认使用8192个字节或字符的缓冲区。缓冲流要套接在相应的节点流之上。
根据数据操作单位可以把缓冲流分为:
BufferedInputStream
和BufferedOutputStream
;BufferedReader
和BufferedWriter
。当使用
BufferedInputStream
读取字节文件时,BufferedInputStream
会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,
BufferedOutputStream
才会把缓冲区中的数据一次性写到文件里。使用方法flush()
可以强制将缓冲区的内容全部写入输出流。关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流。
如果是带缓冲区的流对象的
close()
方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。
5.1、使用缓冲流实现文件拷贝
import java.io.*;
public class MyTest9 {
public static void main(String[] args) throws IOException {
BufferedReader rd = new BufferedReader(new FileReader("C:\\Users\\Maxwell\\Desktop\\a.txt"));
BufferedWriter wr = new BufferedWriter(new FileWriter("C:\\Users\\Maxwell\\Desktop\\b.txt"));
char[] temp = new char[1024];
int len = 0;
while ((len = rd.read(temp)) != -1) {
wr.write(temp, 0, len);
}
wr.close();
rd.close();
}
}
5.2、按行读取
public class MyTest10 {
public static void main(String[] args) throws IOException {
//字符过滤流---缓冲区---BufferdReader
//打开流
FileReader rd = new FileReader("C:\\Users\\Maxwell\\Desktop\\a.txt");
/*
* Reader in = rd;向上转型 多态
* BufferedReader in = new BufferedReader(in);
* */
BufferedReader in = new BufferedReader(rd);
//读---控制台
String line = null;
while((line = in.readLine()) != null) {
System.out.println(line);
System.out.println("-----------------------------------------");
}
//关闭
in.close();
}
}