File类:java.io.File,也是io流中的一部分,File类可以新建、删除、重命名文件与目录,可是不能访问文件自己,如果须要访问文件内容须要使用到输入输出流。html
建立对象:经过构造器获取,介绍三个java
File(String pathname)
:可填入绝对路径与至关路径,相对路径就是在本项目目录下。File(String parent, String child)
:parent是父路径、child是子文件路径。File(File parent, String child)
:父File对象与子文件路径。@Test public void test01(){ //第一个构造器:File(String pathname) File file = new File("C:\\Users\\93997\\Desktop\\fileexer\\javahoner"); //第二个构造器:File(String parent, String child) File file1 = new File("C:\\Users\\93997\\Desktop\\fileexer","javahoner"); //第三个构造器:File(File parent, String child) File file2 = new File(new File("C:\\Users\\93997\\Desktop\\fileexer"),"javahoner"); System.out.println(file); System.out.println(file1); System.out.println(file2); }
string path
。File
类其toString()方法就是打印了String path
参数。路径分隔符:就是上面构造器中的那个\\
,不一样操做系统使用的也不一样c++
windows与Dos系统默认:\
数据库
Unix与URL使用:/
windows
由于Java跨平台,因此对于路径分隔符需慎用,Java也给出通用的:File.separator
,咱们在建立实例时可使用这个参数来代替咱们手写/或\。(这个属性是经过调用方法来获取到本地文件系统的默认分隔符)数组
//至关于C:\Users\93997\Desktop\fileexer\javahoner File file = new File("C:\\Users\\93997\\Desktop\\fileexer\"+File.separator+\"javahoner");
获取文件对象的相关信息缓存
String getAbsolutePath()
:获取文件的绝对路径安全
String getPath
:获取路径(也是绝对路径)网络
String getName
:获取路径下的最后一个文件名app
String getParent()
:获取上层文件目录路径,若无,返回null
Long length()
:获取文件长度(字节数)
Long lastModified()
:获取最后一次修改文件的时间戳(毫秒值)
String[] list()
:获取指定目录下全部文件的名称
File[] listFiles()
:获取指定目录下全部文件,以对象形式返回
.....
实际使用:
@Test public void test01(){ //第一个构造器:File(String pathname) File file = new File("C:\\Users\\93997\\Desktop\\fileexer\\javahoner"); System.out.println(file.getAbsolutePath());//C:\Users\93997\Desktop\fileexer\javahoner System.out.println(file.getPath());//C:\Users\93997\Desktop\fileexer\javahoner System.out.println(file.getName());//javahoner System.out.println(file.getParent());//C:\Users\93997\Desktop\fileexer System.out.println(file.length());//0 System.out.println(file.lastModified());//1612056310161 for (String childFile : file.list()) { System.out.print(childFile+" "); }//文件1 文件2 System.out.println(); for (File listFile : file.listFiles()) { System.out.println(listFile); } //C:\Users\93997\Desktop\fileexer\javahoner\文件1 //C:\Users\93997\Desktop\fileexer\javahoner\文件2 }
方法介绍
public boolean renameTo(File dest)
:剪切文件更名到指定路径(也能够实现重命名效果)
实际应用:重命名与剪切功能
场景1:想将javahoner目录下的文件名为文件
修改成长路锅锅
File file = new File("C:\\Users\\93997\\Desktop\\fileexer\\javahoner\\文件"); boolean b = file.renameTo(new File("C:\\Users\\93997\\Desktop\\fileexer\\javahoner\\重命名的文件")); System.out.println(b);
C:\\Users\\93997\\Desktop\\fileexer\\javahoner\\文件
先剪切到C:\\Users\\93997\\Desktop\\fileexer\\javahoner
路径下再更名为不存在的文件名为重命名文件。实现了修更名称效果场景2:想将javahoner目录下的文件长路锅锅移动到1(2)文件中
File file = new File("C:\\Users\\93997\\Desktop\\fileexer\\javahoner\\长路锅锅"); boolean b = file.renameTo(new File("C:\\Users\\93997\\Desktop\\1(2)\\长路锅锅")); System.out.println(b);
总结:秒呀这个方法,看了下源码最终定位到一个WinNTFileSystem
的private native boolean rename0(File f1, File f2);
根据native关键字,说明这个方法是一个原生函数,是使用c/c++来实现并编译成DLL文件由java去调用。
这里仅仅介绍下方法使用
public boolean isDirectory
:判断是不是文件目录
public boolean isFile()
:判断是不是文件
public boolean exists()
:判断是否存在
public boolean canRead()
:判断是否可读
public boolean canWrite()
:判断是否可写
public boolean is Hidden()
:判断是否隐藏
建立功能
public boolean createNewFile()
:文件存在不建立返回false。
public boolean mkdir()
:文件目录存在不建立,若此文件目录的上级目录不存在也不建立。
public boolean mkdirs()
:不只仅是此目录文件,如果此目录的上层文件目录不存在一并建立。
删除功能
public boolean delete()
:删除此抽象路径名表示的文件或目录,如果此路径名表示目录,则目录必须为空才能删除。
案例:删除指定路径下全部文件
public class Main { //生成num个空白字符串,如果num非0最后添加- public static String blankStr(int num){ StringBuilder str = new StringBuilder(); for (int i=0;i<num;i++){ str.append(" "); } if(num != 0){ str.append("-"); } return str.toString(); } //删除路径下内容(包含层级关系) public static void deleteAllFile(File file,int tier) throws RuntimeException{ //若是该路径是一个文件直接删除 if(file.isFile()){ System.out.println(file.delete()?blankStr(tier)+file.getName()+"已删除":blankStr(tier)+file.getName()+"删除失败"); return; } //该路径是目录 File[] files = file.listFiles(); //空目录直接删除 if(files == null || files.length == 0){ System.out.println(file.delete()?blankStr(tier)+"成功删除"+file.getName():blankStr(tier)+file.getName()+"空目录删除失败"); return; } //目录不为空,遍历当前文件 for (File dict : files) { //目录:删除目录中内容+删除本身自己 if(dict.isDirectory()){ //获取目录下的全部文件 File[] files2 = dict.listFiles(); //若是目录为空直接删除 if(files2 == null || files2.length == 0){ System.out.println(dict.delete()?blankStr(tier)+"成功删除"+dict.getName():blankStr(tier)+dict.getName()+"空目录删除失败"); }else{ //非空目录状况 deleteAllFile(dict,tier+1); System.out.println(dict.delete()?blankStr(tier)+"成功删除"+dict.getName():blankStr(tier)+dict.getName()+"空目录删除失败"); } }else{ //非目录:无提示直接调用 deleteAllFile(dict,tier+1); } } } //测试 @Test public void test01(){ File file = new File("C:\\Users\\93997\\Desktop\\fileexer\\javahoner\\文件1"); try { deleteAllFile(file,0); } catch (RuntimeException e) { System.out.println("删除非空文件时出现异常!!!"); } System.out.println("该文件路径下内容已被删除"); } }
deleteAllFile(File file,int tier)
便可:参数1就是删除指定文件路径,参数2表示层级关系(设置为0最高级)Google将I/O誉为"开放中创新",input/output:二进制1,0
IO原理
:是Input/Output的缩写,I/O技术是很实用的技术,用来处理设备之间的数据传输。例如读/写文件,网络通信等。
在Java程序中,对于数据的输入/输出操做以"流(stream
)"的方式进行。java.io包下提供了各类"流"类和接口,用以获取不一样种类的数据,并经过标准的方法输入或输出数据。
流的分类
根据数据单位不一样分为两类:字节流与字符流
byte
的流,一般用来传输视频、图片(非文本的数据)char
的流,一般用来文本输入输出。
数据的流向不一样分为:输入流、输出流
角色不一样分为:节点流、处理流
Java的IO流所有都是由下面这4个抽象基类派生:
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
I/O流体系图:
关系图:
对于字节流的输入输出流的基类,首先介绍一下InputSream
以及OutputSream
。
InputSream
为字节输入流的抽象基类,其基类定义了如下几个通用方法,这里列举几个
int read()
:从流中读取1个字节并返回,若是达到文件末尾返回-1;read(byte b[])
:从流中读取b的长度个字节的数据存储到b中,返回的是读取的字节个数,如果返回-1表示到告终尾,没有数据。int read(byte b[], int off, int len)
:从流中的off位置开始读取len个字节的数据到b中,返回结果是实际读取的字节个数,如果返回-1表示没有数据。void close()
:关闭输入流OutputSream
为字节输出流的抽象基类,这里列举几个该基类经常使用方法
void write(int b)
:将1个字节写入到输出流中void write(byte b[])
:从b的off位置开始,获取len个字节数据,写到输出流中void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。(为以后缓冲流提供抽象方法)void close()
:关闭输出流输出入流关字节流的含节点流以及各类处理流它们的基类就是这两个。
对于字符流的输入输出流的基类,介绍一下Reader
、Writer
Reader
:是字符输入流的抽象基类 ,定义了几个函数以下
int read()
:读取单个字符,返回结果是一个int,若想要字符显示须要转为char;如果到达流的末尾,返回-1int read(char cbuf[])
:从流中读取b的长度个字符的数据存储到b中,返回的是读取的字节个数,如果返回-1表示到告终尾,没有数据。void close()
:关闭字符输入流writer
:是字符输入流的抽象基类 ,定义了几个函数以下
void write(int b)
:将1个字节写入到输出流中void write(byte b[])
:从b的off位置开始,获取len个字节数据,写到输出流中void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。(为以后缓冲流提供抽象方法)void close()
:关闭输出流与以前介绍的字节流大体相同,他们两个区别之一就是它们传递的数据单位不一样一个是字节、一个是流。
节点流也称文件流,对应节点流包含了字节流与字符流
FileInputSream
、FileOutputSream
FileReader
、FileWriter
案例1:使用字节流来复制图片
import org.junit.Test; import java.io.*; public class Main { @Test public void test02(){ FileInputStream fis = null; FileOutputStream fos = null; try { //目标图片1234.jpg fis = new FileInputStream(new File("1234.jpg")); //复制地址 fos = new FileOutputStream(new File("图片.jpg")); byte[] data = new byte[1024]; int len; //读取字节 while((len = fis.read(data)) != -1){ //写入data数组中读取到的len个字节 fos.write(data,0,len); } } catch (IOException e) { e.printStackTrace(); }finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if(fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
案例2:复制文本文件,而且在控制台显示
import org.junit.Test; import java.io.*; public class Main { //这里主要为了演示就不像以前那么规范,直接抛出异常 @Test public void test02() throws IOException { FileReader fr = new FileReader("changlu.txt");; FileWriter fw = new FileWriter("cl.txt"); char[] data = new char[1024]; int len; while((len = fr.read(data)) != -1){ //显示在控制台中 System.out.print(new String(data,0,len)); fw.write(data,0,len); } fr.close(); fw.close(); } }
FileWriter(File file, boolean append)
这种构造器方式,第二个参数填true表示数据写入从文件末尾开始。首先看一下缓冲流,前两个是用于传输字节的缓冲流,后两个是传输字符的缓冲流
看一下继承关系:
传输字节的两个缓冲流都是继承于FilterInputStream:
传输字符的两个缓冲流都是继承于Writer
缓冲流的做用:提升文件的读写效率
提升读写速度的缘由:内部提供了一个缓冲区
使用了缓冲区与没有使用的图示:
实际上使用缓冲流很简单,直接在节点流上包一层,缓冲流也是须要进行手动关闭的,关闭的同时会将节点流也关闭。
示例:这里
//字节流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("changlu.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("test.txt"))); //字符流 BufferedReader br = new BufferedReader(new FileReader("file.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("file2.txt"));
针对于缓冲流本身实现了一个方法
void newLine()
:向文件中写入换行符通常写入完以后咱们还须要使用flush()
方法来将缓存区的内容手动写入到文件中。
测试复制66MB的视频速度:
介绍图片加密的方法:
//加密data数组中0-len中的字节 public static byte[] encryptChar(byte[] data,int len){ for (int i = 0; i < len; i++) { data[i] ^= 5;//经过异或的方式 } return data; } //写入操做 省略了内容 byte[] data = new byte[1024]; int len; //读取字节 while((len = bis.read(data)) != -1){ //写入data数组中读取到的len个字节 bos.write(encryptChar(data,len)); }
转换流提供了在字节流和字符流之间的转换
InputStreamReader
:将InputStream转换为Reader 字节转字符OutputStreamWriter
:将Writer转换为OutputStream 字符转字节当字节流中的数据都是字符时,转成字符流更高效。大多经过使用转换流来处理文件乱码问题,实现编码和解码功能!
简单举个例子:将changlu.txt(UTF-8编码)先经过InputStreamReader
转为字符,再经过使用OutputStreamWriter
指定另外一个编码转为长changlu.txt。(gbk编码)
转换流的编码应用:
使用转换流将一个UTF-8编码文件转为GBK编码的文件
public class Main { public static void main(String[] args) throws IOException { //转换流 将一个UTF-8编码的转为GBK编码的 InputStreamReader isr = new InputStreamReader(new FileInputStream("changlu.txt"), StandardCharsets.UTF_8); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("changluya.txt"), "GBK"); //使用缓冲流加速 BufferedReader br = new BufferedReader(isr); BufferedWriter bw = new BufferedWriter(osw); char[] data = new char[1024]; int len; while((len = br.read(data)) != -1){ bw.write(data,0,len); } br.close(); bw.close(); } }
系统标准的输入和输出设备分别为:System.in与System.out。默认输入设备:键盘;默认输出设备:显示器
System.in
:实际类型为InputStream
System.out
:实际类型为PrintStream
,其次是OutputStream的子类咱们能够更改System的输入输出设备经过System的的setIn
,setOut
方法。
传统咱们经过使用Scanner
来进行数据的输入获取,在这里不容许使用Scanner
,要求从键盘输入字符串,要求将读取到的整行字符串转成大写输出。而后继续 进行输入操做,直至当输入“e”或者“exit”时,退出程序。
public static void main(String[] args) throws IOException { //System.in是InputStream实例(字节流),这里包一层转换流转换为字符流 InputStreamReader is = new InputStreamReader(System.in); //包装上一层缓冲流 BufferedReader br = new BufferedReader(is); String str; //键盘中每读取一行数据进行循环 while((str = br.readLine()) != null){ if("e".equals(str) || "exit".equals(str)){ System.out.println("安全退出"); break; } str = str.toUpperCase(); //System.out => PrintStream System.out.println(str); System.out.println("继续输入信息"); } br.close(); }
实现将基本数据的类型格式转换为字符串输出
PrintStream
打印的全部字符都使用平台的默认字符编码转换为字节,在须要写入字符而不是写入字节的状况下应该使用PrintWriter
单个介绍:
PrintStream
:在实现OutputStream接口上又实现了打印各类数据的print方法,一般使用系统默认的System.out
调用方法输出
PrintWriter
:扩展了Write接口,也实现了许多print打印输出方法
属于字符流
最终输出的是char字符
//使用方式:配合StringWriter获取数据并打印到控制台 public static void main(String[] args) throws IOException { //内部定义了一个StringBuffer存储数据 StringWriter str = new StringWriter(); try (PrintWriter pw = new PrintWriter(str)){ //将指定内容写入到str中,实际上仍是调用了write方法 pw.println("hello"); pw.println("changlu"); pw.println(2020); } //将StringBuffer对象打印 System.out.println(str.toString()); }
案例描述:将本来输出到控制台的内容输入到文件中
思路:更改System中的输出设备(显示屏 =》文件)
public static void main(String[] args) throws IOException { //try(声明1;声明2;){ ... } 这种方式会自动执行close()方法 try(//①建立文件字节流 FileOutputStream fos = new FileOutputStream("changlu.txt"); //②PrintStream处理流包裹节点流 PrintStream ps = new PrintStream(fos);){ //更改System的输出设备为文件流 System.setOut(ps); //输出到文件中 System.out.println("长路&林儿"); } }
执行结果:成功建立changlu.txt,并输入到文件中。
InputStream
和OutputStream
子类的流上。目的:为了方便操做Java的基本数据类型与String类型,可使用数据流。
这里列举一下DataInputStream
的几个方法以下:byte readByte()
、char readChar()
、float readFloat()
、long readLong()
、int readInt()
、String readUTF()
int readInt()
一次性读出四个字节并将其转为int值读出OutputStream
几个相似read换write便可。
void writeInt(int v)
一次写入四个字节并将其转为字节写出直接上小案例:输出流与输入流配合使用(增添了一个缓冲流来提高速度)
public class Main { //使用数据流的输出流存储不一样类属数据 @Test public void test01(){ try(BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream("changlu.data")); DataOutputStream dos = new DataOutputStream(bis);){ dos.writeUTF("长路"); dos.writeInt(666); dos.writeBoolean(false); dos.flush(); } catch (IOException e) { e.printStackTrace(); } } //使用数据流的输入流来获取指定顺序的数据类型 @Test public void test02(){ try(BufferedInputStream bos = new BufferedInputStream(new FileInputStream("changlu.data")); DataInputStream dis = new DataInputStream(bos);) { String name = dis.readUTF(); int num = dis.readInt(); boolean bol = dis.readBoolean(); System.out.println(name+"\n"+num+"\n"+bol); } catch (IOException e) { e.printStackTrace(); } } }
详细对象流以及序列化见:IO流—对象序列化
接下来要介绍的随机存取文件流只有一个类RandomAccessFile
,它实现了DataOutput
、DataInput
接口,直接继承于Object,说明其实现了读取与写入的功能。
RandomAccessFile
类功能描述:
long getFilePointer()
获取指针的位置,void seek(long pos)
将指针定位到pos位置。构造器介绍:RandomAccessFile(String name, String mode)
、RandomAccessFile(File file, String mode)
r
:只读方式打开。rw
:打开以便读取和写入。rwd
:打开以便读取和写入;同步文件内容的更新。rws
:打开以便读取与写入;同步文件内容和元数据的更新。注意点:若模式为r
(只读),不可以建立文件,只能读取存在的文件,如果不存在就会出现异常;rw
模式是如果不存在就会去建立文件。
rw
模式,数据不会当即写入到硬盘中,一旦写入过程当中有异常数据所有丢失;rwd
模式数据会被当即写入硬盘。一旦写数据发生异常,rwd
模式中会将已被写入的数据保存到硬盘中。案例1:复制图片
@Test public void test01(){ //建立两个随机存取流的实例对象,分为来进行读或写的操做 try(RandomAccessFile rafRead = new RandomAccessFile("1234.jpg", "r"); RandomAccessFile rafWrite = new RandomAccessFile("changlu.jpg", "rw");){ byte[] data = new byte[1024]; int len; while((len = rafRead.read(data))!=-1){ rafWrite.write(data,0,len); } }catch (IOException e) { e.printStackTrace(); } }
案例2:复制一个文件中的内容到另外一个文件追加内容
@Test public void test01(){ //建立两个随机存取流的实例对象,分为来进行读或写的操做 try(RandomAccessFile rafRead = new RandomAccessFile("changlu.txt", "r"); RandomAccessFile rafWrite = new RandomAccessFile("changlu222.txt", "rw");){ //获取其中的字节 int fileLength = (int) rafRead.length(); byte[] data = new byte[fileLength]; for(int i=0;i<data.length;i++){ data[i] = rafRead.readByte(); } //复制内容到其余文件中 rafWrite.seek(2);//空两格 for(int i = 0 ;i<data.length;i++){ rafWrite.writeByte(data[i]); } //新增指定内容 // byte[] bytes = "想对林儿说我想你了".getBytes("utf-8"); // for(int i=0;i<bytes.length;i++){ // rafWrite.writeByte(bytes[i]); // } rafWrite.writeUTF("想对林儿说我想你了"); }catch (IOException e) { e.printStackTrace(); } }
出现乱码,比较迷糊搞不清
java.nio这个类带来了重要的效能提高并能够充分利用执行程序的机器上的原始容量。
java1.4版新增的输入输出java.nio这个类带来了重要的效能提高并能够充分利用执行程序的机器上的原始容量。
包含一项关键能力是能够直接控制buffer
以及nonblocking
的输入域输出,它能让你的输入/输出程序代码在没有东西可读取或写入
时不用等在那里。
对于nio可能会引起效能损失,非nio的输入/输出适合九成以上的应用,依旧可使用FileInputStream
并经过getChannel()
方法来开始使用nio。
NIO.2中Path、Paths、Files类的使用见:语雀-NIO部分
[1]. Java中Native关键字的做用
[2]. Java一个汉字占几个字节(详解与原理) 特别详细
[3]. 为何用字符流复制的图片打不开,而用字节流复制的却能够打开?
[4]. 对比字节流和字符流,回答为何FileReader不能用来拷贝图片
[5]. Java I/O流之随机流详解,包含随机流读写数据时编码格式问题!
[6]. 尚硅谷Java视频-IO流(宋红康)
我是长路,感谢你的阅读,若有问题请指出,我会听取建议并进行修正。 欢迎关注个人公众号:长路Java,其中会包含软件安装等其余一些资料,包含一些视频教程以及学习路径分享。 学习讨论qq群:891507813 咱们能够一块儿探讨学习 注明:转载可,须要附带上文章连接