1.认识文件
我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进⾏数据保存时,往往不是保存成⼀个整体,⽽是独⽴成⼀个个的单位进⾏保存,这个独⽴的单位就被抽象成⽂件的概念,就类似办公桌上的⼀份份真实的⽂件⼀般。.
什么是输入输出?
靠近cpu就是输入,远离cpu就是输出。
例如下载一个文件,把文件从网卡下载到硬盘上就是输入,把文件上传到网卡上就是输出
文件夹也是一种文件,我们称为"目录文件"(diectory),这种文件之间的嵌套关系是一种树型结构,n叉树。
文件路径
分为绝对路径和相对路径。
绝对路径:以盘符开头的我们称为绝对路径
相对路径,可以是任意路径。例如:
在D:\qq\program\Bin\qq.exe找一个qq.exe,当我们在program中我们可以用./Bin/qq.exe('./'可以省略)。这里的一个.表示当前位置。两个点表示前一级例如我们现在在\Bin\plugins,则用.../qq.exe
在windows中我,可以用'/'或'\'来写路径名称。但是linuix,Mac等其他一般都是'\'所以推荐写正斜杠。
区分文本文件和二进制文件
本质上来说无论是文本文件还是二进制文件都存放的是0101这样的二进制数据。不同的是文本文件存的数据可以构成合法字符。
为什么要区分文本文件和二进制文件?
编译处理的过程,处理方式(写的代码)是不同的
如何区分?用记事本,如果是乱码就是二进制文件,不是乱码就是文本文件
对文件系统进行操作
File类来自于java.io包
方法:
mkdir只能创建一个目录文件,而mkdirs可以创建多层目录文件
文件内容操作
在java中通过"流"这样的一组类,进行上述内容操作
分为两组
1.字节流(以字节为单位,读写数据)处理二进制文件
InputStream
方法1:
java
public static void main(String[] args)throws IOException {
InputStream inputStream=new FileInputStream("D:/note/text/123.txt");
while (true){
int a=inputStream.read();
//一次read一个字节,参数是int类型
if (a==-1){
break;
}
System.out.printf("0x%x ",a);
}
}
方法2:
java
public static void main(String[] args)throws IOException {
InputStream inputStream=new FileInputStream("D:/note/text/th.jpg");
//如果大于1024个字节那么一次读不完,那么while再申请1024个字节,直到小于1024结束时返回-1
while (true){
byte[] bytes=new byte[1024];
int n=inputStream.read(bytes);
//一次读1024个字节,
System.out.println("n="+n);
if(n==-1){
break;
}
for (int i = 0; i < n; i++) {
System.out.printf("0x%x ",bytes[i]);
}
}
}
相比于方法一,从硬盘读一次打印一次方法二直接将硬盘内容读到数组中效率更高
read完之后要关闭文件,因为再你打开文件的时候,会在pcb结构体中,给文件描述符表添加一个元素,因为文件描述符表是有上限的,一旦你重复打开而不关闭就会占满文件描述符表,下次打开文件就会打开失败。
如何避免这种错误发生?
1.读完操作后加上close方法
2.利用try{}finally{}
java
public static void main(String[] args)throws IOException {
InputStream inputStream=null;
try{
inputStream=new FileInputStream("D:/note/text/th.jpg");
while (true){
byte[] bytes=new byte[1024];
int n=inputStream.read(bytes);
System.out.println("n="+n);
if(n==-1){
break;
}
for (int i = 0; i < n; i++) {
System.out.printf("0x%x ",bytes[i]);
}
}
}finally{
assert inputStream != null;
inputStream.close();
}
}
3.把流对象创建,写到try()里之后,此时,代码执行出了try{}时,就会自动调用inputStream的close了,此语法称try with resource
注意:只能是实现Closeable接口的类,才能放到try()里
java
public static void main(String[] args) throws IOException {
try (InputStream inputStream=new FileInputStream("D:/note/text/123.txt")){
while (true){
byte[] bytes=new byte[1024];
int n=inputStream.read(bytes);
if(n==-1){
break;
}
for (int i = 0; i <n ; i++) {
System.out.printf("0x%x ",bytes[i]);
}
}
}
}
总结,字节流通过对字节的读取或写的方式进行操作,
OutputStream
java
public static void main(String[] args) throws IOException {
try(OutputStream outputStream=new FileOutputStream("D:/note/text/123.txt")){
outputStream.write(97);
outputStream.write(98);
}
}
通过二进制写,将二进制数据存入文件中
按照这样写会将文本中原有数据清空,不是write清空,而是打开操作清空的。使用追加写的方式可以避免此情况
java
public static void main(String[] args) throws IOException {
//这里后面的true就是是否要append(追加)
try(OutputStream outputStream=new FileOutputStream("D:/note/text/123.txt",true)){
outputStream.write(97);
outputStream.write(98);
}
}
2.字符流(以字符为单位,读写数据)处理文本文件
Reader
一次读取一个字符
java
//这个地址里面放的时"你好世界"
public static void main(String[] args) throws IOException {
try(Reader reader=new FileReader("D:/note/text/147.txt")){
while (true){
int n=reader.read();
if (n==-1){
break;
}
char b=(char) n;
System.out.println(b);
}
}
}
一次读取1024个字符
java
public static void main(String[] args) throws FileNotFoundException {
try(Reader reader=new FileReader("D:/note/text/147.txt")){
while (true){
char[] a=new char[1024];
int n=reader.read(a);
if(n==-1){
break;
}
for (int i = 0; i < n; i++) {
System.out.println(a[i]);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Writer
(一个字符对应几个字节取决于编码方式,jdk2个,utf8是3个)
一次写一个
java
public static void main(String[] args) {
try(Writer writer=new FileWriter("D:/note/text/147.txt",true)) {
writer.write("xxx");
} catch (IOException e) {
throw new RuntimeException(e);
} ;
}
一次写多个
java
public static void main(String[] args) throws IOException {
try(Writer writer=new FileWriter("D:/note/text/147.txt",true)){
char[] a=new char[1024];
for (int i = 0; i < 4; i++) {
a[i]='w';
}
writer.write(a);
}
}