java.io.File类::文件和文件目录路径的抽象表示形式,与平台无关
File类的一个对象就代表一个文件或一个文件目录(俗称文件夹)
public File(String pathname) 以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果 pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
绝对路径:是一个固定的路径,从盘符开始 相对路径:是相对于某个位置开始
public File(String parent,String child) 以parent为父路径,child为子路径创建File对象。
public File(File parent,String child) 根据一个父File对象和子文件路径创建File对象
//实例化File对象
@Test
public void test1(){
//构造器一
File file = new File("hello.txt");//相对路径:IDEA 的module下
File file1 = new File("E:\\Workspace_idea01\\JavaSenior\\he.txt");//绝对路径:包含盘符
//构造器二
File file2 = new File("E:\\Workspace_idea01\\", "JavaSenior");
System.out.println(file2);
//构造器三
File file3 = new File(file2, "hi.txt");
}
路径中的每级目录之间用一个路径分隔符隔开。
路径分隔符和系统有关:
Java程序支持跨平台运行,因此路径分隔符要慎用。
为了解决这个隐患,File类提供了一个常量: public static final String separator。根据操作系统,动态的提供分隔符。
File file1 = new File("d:\\zck\\info.txt");
File file2 = new File("d:" + File.separator + "zck" + File.separator + "info.txt");
File file3 = new File("d:/zck");
public String getAbsolutePath():获取绝对路径
public String getPath() :获取路径
public String getName() :获取名称
public String getParent():获取上层文件目录路径。若无,返回null
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值
@Test
public void test2(){
File file1 = new File("hello.txt");//已创建:内容为hello123
File file2 = new File("e:\\io\\hi.txt");//未创建
System.out.println(file1.getAbsolutePath());
System.out.println(file1.getPath());
System.out.println(file1.getName());
System.out.println(file1.getParent());
System.out.println(file1.length());
System.out.println(new Date(file1.lastModified()));
System.out.println();
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());
System.out.println(file2.getName());
System.out.println(file2.getParent());
System.out.println(file2.length());
System.out.println(file2.lastModified());
}
程序执行结果
E:\Workspace_idea01\JavaSenior\hello.txt
hello.txt
hello.txt
null
8
Fri Apr 10 13:49:49 CST 2020d:\io\hi.txt
d:\io\hi.txt
hi.txt
d:\io
0
0
如下的两个方法适用于文件目录:
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
@Test
public void test3(){
File file = new File("E:\\Workspace_idea01");
String[] list = file.list();
for (String s : list){
System.out.println(s);
}
System.out.println("********************");
File[] files = file.listFiles();
for (File f : files){
System.out.println(f);
}
}
程序执行结果
.idea
JavaSeniorE:\Workspace_idea01.idea
E:\Workspace_idea01\JavaSenior
public boolean renameTo(File dest):把文件重命名为指定的文件路径
要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。
@Test
public void test4(){
File file1 = new File("hello.txt");
File file2 = new File("E:\\io\\hi.txt");
boolean renameTo = file2.renameTo(file1);
System.out.println(renameTo);//若E:\\io\\hi.txt存在,返回false
}
public boolean isDirectory():判断是否是文件目录
public boolean isFile() :判断是否是文件
public boolean exists() :判断是否存在
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏
创建硬盘中对应的文件或文件目录
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs() :创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,一并创建
删除磁盘中的文件或文件目录
public boolean delete():删除文件或者文件夹
删除注意事项:Java中的删除不走回收站。
@Test
public void test4() throws IOException {
File file1 = new File("hi.txt");
if(!file1.exists()){
//文件的创建
file1.createNewFile();
System.out.println("创建成功");
}else{
//文件存在
file1.delete();
System.out.println("删除成功");
}
}
@Test
public void test5(){
//文件目录的创建
File file1 = new File("e:\\io\\io1\\io3");
boolean mkdir = file1.mkdir();
if(mkdir){
System.out.println("创建成功1");
}
File file2 = new File("e:\\io\\io1\\io4");
boolean mkdir1 = file2.mkdirs();
if(mkdir1){
System.out.println("创建成功2");
}
//要想删除成功,io4文件目录下不能有子目录或文件
File file3 = new File("E:\\io\\io1\\io4");
file3 = new File("E:\\io\\io1");
System.out.println(file3.delete());
}
}
I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于 处理设备之间的数据传输。如读/写文件,网络通讯等。
IO原理:
按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
按数据流的流向不同分为:输入流,输出流
按流的角色的不同分为:节点流,处理流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
注:Java的IO流共涉及40多个类,实际上非常规则,都是从如下4个 抽象基类派生的。
由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
//1.建立一个流对象,将已存在的一个文件加载进流。
FileReader fr = new FileReader(new File(“Test.txt”));
//2.创建一个临时存放数据的数组。
char[] ch = new char[1024];
//3.调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);
//4. 关闭资源。
fr.close();
举例:
package com.zck.iotest;
import org.junit.Test;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
* @author zck
* @create 2020-04-11 11:00
*/
public class FileTest1 {
/*
读取当前module下的hello.txt文件(已创建),并输出到控制台
*/
@Test
public void testFileReader() {
FileReader fr = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("hello.txt");
//2.提供具体的流
fr = new FileReader(file);
//3.数据的读入
int date;
while ((date = fr.read()) != -1) {
//read():返回读入的一个字符。如果达到文件末尾,返回-1
System.out.print((char) date);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
对read()操作升级:使用read的重载方法
read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
*/
@Test
public void testFileReader1() {
FileReader fr = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("hello.txt");
//2.提供具体的流
fr = new FileReader(file);
//3.数据的读入
char[] cbuf = new char[5];
int len;
while ((len = fr.read(cbuf)) != -1) {
//方式一:
// for (int i = 0; i < len; i++) {
// System.out.print(cbuf[i]);
// }
//方式二:
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
对当前module下的hello.txt文件(已创建)进行写出操作:从内存中写出数据到硬盘的文件里。
说明:
1. 写出操作,对应的File可以不存在的。并不会报异常
2.
File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
File对应的硬盘中的文件如果存在:
如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容
*/
@Test
public void testFileWriter(){
FileWriter fw = null;
try {
//创建流并指明操作的文件对象
fw = new FileWriter(new File("hello1.txt"), false);
//写出操作
fw.write("I love learning JAVA\n");
fw.write("I can succeed");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流资源
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.zck.iotest;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author zck
* @create 2020-04-11 10:22
*/
/*
使用节点流(文件流)对非文本文件(视频、音频、doc、pdf...)进行一个复制操作
*/
public class FileTest {
public void copyFile(String srcPath, String destPath) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//1.造文件:实例化File类的对象,指明要操作的文件
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//2.造流:提供具体的流
fis = new FileInputStream(srcPath);
fos = new FileOutputStream(destPath);
//3.复制
byte[] buffer = new byte[1024];
int len;//记录每次读入buffer的字节个数
while ((len = fis.read(buffer)) != -1) {
//如果达到文件末尾,返回-1
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭资源
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void test1() {
//举例测试
long start = System.currentTimeMillis();
String srcPath = "C:\\Users\\hd\\Desktop\\《Effective Java中文版 第2版》.pdf";
String destPath = "C:\\Users\\hd\\Desktop\\《Effective Java中文版 第2版》1.pdf";
copyFile(srcPath, destPath);
long end = System.currentTimeMillis();
System.out.println("复制花费的时间:" + (end - start));//755
}
}
Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。、提高数据读写的速度
package com.zck.iotest;
import org.junit.Test;
import java.io.*;
/**
* @author zck
* @create 2020-04-11 11:40
*/
public class BufferedTest {
/*
使用缓冲流对非文本文件(视频、音频、doc、pdf...)进行一个复制操作
*/
public void copyFile(String srcPath, String destPath) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件:实例化File类的对象,指明要操作的文件
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//2.造流:提供具体的流
//2.1造节点流
FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制
byte[] buffer = new byte[1024];
int len;//记录每次读入buffer的字节个数
while ((len = bis.read(buffer)) != -1) {
//如果达到文件末尾,返回-1
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭资源
try {
if(bis != null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void test1(){
long start = System.currentTimeMillis();
String srcPath = "C:\\Users\\hd\\Desktop\\《Effective Java中文版 第2版》.pdf";
String destPath = "C:\\Users\\hd\\Desktop\\《Effective Java中文版 第2版》1.pdf";
copyFile(srcPath, destPath);
long end = System.currentTimeMillis();
System.out.println("复制花费的时间:" + (end - start));//755 ---》202
}
}
/*
使用BufferedReader和BufferedWriter实现文本文件的复制
*/
@Test
public void testBufferedReaderBufferedWriter() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件和相应的流
br = new BufferedReader(new FileReader(new File("hello.txt")));
bw = new BufferedWriter(new FileWriter(new File("hello1.txt")));
//读写操作
//方式一:使用char[]数组
// char[] cbuf = new char[1024];
// int len;
// while((len = br.read(cbuf)) != -1){
// bw.write(cbuf,0,len);
// // bw.flush();
// }
//方式二:使用String
String data;
while ((data = br.readLine()) != null) {
//方法一:
// bw.write(data + "\n");//data中不包含换行符
//方法二:
bw.write(data);//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();
}
}
}
}
转换流提供了在字节流和字符流之间的转换(字节-----字符-----字节):先解码,后编码
编码:字符串-----》字节数组
解码:字节数组------》字符串
Java API提供了两个转换流
字节流中的数据都是字符时,转成字符流操作更高效。
很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
编码表的由来:计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识 别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。 这就是编码表。
常见的编码表:
ASCII:美国标准信息交换码。 用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表 用一个字节的8位表示。
GB2312:中国的中文编码表。最多两个字节编码所有字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯 一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。推荐的 Unicode编码是UTF-8和UTF-16。
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
UTF8就是每次8个位传输数据,UTF-16就是每次16个位。这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。
System.in和System.out分别代表了系统标准的输入和输出设备
默认输入设备是:键盘,输出设备是:显示器
System.in的类型是InputStream
System.out的类型是PrintStream,其是OutputStream的子类 FilterOutputStream 的子类
重定向:通过System类的setIn(),setOut()对默认设备进行改变。
实现将基本数据类型的数据格式转化为字符串输出
打印流:PrintStream和PrintWriter
数据流有两个类:(用于读取和写出基本数据类型、String类的数据)
DataInputStream 和 DataOutputStream
分别“套接”在 InputStream 和 OutputStream 子类的流上
可以更方便地操作Java语言的基本数据类型和String的数据。
用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
ObjectInputStream(进行反序列化)和OjbectOutputSteam(进行序列化)
补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
序列化:使用ObjectOutputStream类实现将内存中的java对象、基本数据类型保存到磁盘中,或通过网络传输出去
反序列化:使用ObjectInputStream类实现將磁盘文件中的对象还原为内存中的一个java对象
package com.zck.iotest;
import org.junit.Test;
import java.io.*;
/**
* 对象流的使用
*
* @author zck
* @create 2020-04-11 15:13
*/
public class ObjectInputStreamTest {
/*
序列化:将内存中的java对象、基本数据类型保存到磁盘中,或通过网络传输出去
使用ObjectOutputStream类实现
*/
@Test
public void test1() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("学习使我强大!!!"));
oos.flush();//刷新操作者
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null)
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
反序列化:將磁盘文件中的对象还原为内存中的一个java对象
使用ObjectInputStream类实现
*/
@Test
public void test2(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object object = ois.readObject();
String str = (String) object;
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
if (ois != null)
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传 输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是 JavaEE 平台的基础
Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的 serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异 常。(InvalidCastException)
随机存取文件流:RandomAccessFile 类
RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。并 且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。
/*
* RandomAccessFile的使用
* 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
* 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
*
* 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
* 如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
*
* 4. 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果
*/
@Test
public void test1() {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
//1.
raf1 = new RandomAccessFile(new File("psycho pass.jpg"),"r");
raf2 = new RandomAccessFile(new File("psycho pass1.jpg"),"rw");
//2.
byte[] buffer = new byte[1024];
int len;
while((len = raf1.read(buffer)) != -1){
raf2.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.
if(raf1 != null){
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(raf2 != null){
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
raf1.write("xyz".getBytes());/
raf1.close();
}
/*
使用RandomAccessFile实现数据的插入效果
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while((len = raf1.read(buffer)) != -1){
builder.append(new String(buffer,0,len)) ;
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
}
}
注:本文章是根据哔哩哔哩公开课 Java -Java 学习- Java 基础到高级-宋红康-零基础自学Java-尚硅谷 整理所得
大爱康师傅!!!