文章目录
- 文件的概念
- 什么是文件?
- 树型结构组织 和 目录
- 文件路径
- 相对路径
- 绝对路径
- 文件的分类
- 文件的权限
- 文件读写IO API
- 字符流操作API
- 警告
- 字节流操作API
- InputStream
- OutputStream
文件的概念
什么是文件?
我们先来理解一下什么是文件,那么想要知道什么是文件的话,我们首先要知道文件是干嘛的,文件其实就是用来保存数据的,我们知道我们电脑产生的数据是保存在了硬盘里的,可是那么多的数据如果我们不进行分类保管的话就会导致所有的数据乱作一团,因此就有了文件,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般,那么我们创建了一个文件但是不往里面写东西那么这个文件有内存吗?也就是说创建一个空的文件,那么这个文件真的就是不占内存吗?显然这个答案是不对的,即使这个文件什么东西也没写他也不可能就一些内存没占,这是为什么呢?
因为一个文件需要储存的其实不止他所包含的数据还有他自己的一些属性比如说这个文件的名称还有这个文件的位置这些属性信息同样也是需要储存的。既然需要储存那就一定占了内存。
树型结构组织 和 目录
前面说了文件里面用来保存了文字数字等内容,可是一堆的文件放在那里也不好看啊,怎么办呢?这时候聪明的人类就想到了一个好点子那就是像文件保存数据一样创造一种类型让他能够保存文件,这个类型就是文件夹。当然了我们应该叫做目录。
这些目录是按照什么进行排列的呢?当然是树形了。我们可以看一下下面这个图
我们可以看到上面的目录和文件的关系其实就是像棵树一样也就是多叉树。
文件路径
既然文件的一个存放是一个多叉树的类型,那么我们应当如何定位一个文件呢?那么这时候就需要文件路径了。
那么文件路径又分为相对路径和绝对路径
相对路径
从任意节点出发到达目标节点的路径称为相对路径。
绝对路径
从根节点出发到达目的节点的方式成为绝对路径。
文件的分类
那么文件分为哪几类呢?文件分为二进制文件和文本文件,那么什么是二进制文件,什么是文本文件呢?二进制文件是指文件中的内容是二进制的形式,这些文件我们人是看不懂的,二进制文件常见的是以bin为结尾,而文本文件常见的是以txt形式为结尾。
文件的权限
关于文件的权限其实windows上体验的其实不是很明显,因为windows中自带的就是管理员权限,但是Linux中感觉就很明显了,那么文件权限的意义是什么呢?文件由于被操作系统进行了管理,所以根据不同的用户,会赋予用户不同的对待该文件的权限,一般地可以认为有可读、可写、可执行权限。
Windows 操作系统上,还有一类文件比较特殊,就是平时我们看到的快捷方式(shortcut),这种文
件只是对真实文件的一种引用而已。其他操作系统上也有类似的概念,例如,软链接(soft link)等。
文件读写IO API
关于文件的操作可以分为两大类,如下图
那么什么是字符流什么又是字节流呢?他们两个区分其实很简单,字符流操作中的基本单位是字符,字节流操作的基本单位是字节。
那么我们来分别进行操作。
字符流操作API
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class test_byte {
public static void main(String[] args) throws IOException {
Reader reader=new FileReader("d:/test.txt");
char[] arr=new char[1024];
reader.read(arr);
System.out.println(arr);
}
}
首先我们先来看一下这个代码假如说我的d盘中没有test.txt那么这个代码可以执行吗?答案是可以的 但是会抛出异常
这里我们可以看到这里的异常说明系统找不到指定文件那么我们将其创建出来。然后我们向里面写一些东西来进行测试
这里我们发现我们输出的东西很奇怪因为他输出了我们写的内容之后有输出了一个很奇怪的字符这是为什么呢?因为我们刚刚对这个字符串类型初始化的是1024个字节,但是这里面的内容很明显没有1024这时候还有一些没被初始化的地方就变成了现在这样了。那么这时候怎么解决呢?
其实很简单我们的render方法是有返回值的他的返回值其实就是,该文件中字符的个数,因为我们是字符流操作的因此他返回的内容就是文件中字符的个数。因此我们只需要对代码进行稍稍的改动即可
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class test_byte {
public static void main(String[] args) throws IOException {
Reader reader=new FileReader("d:/test.txt");
char[] arr=new char[1024];
int n=reader.read(arr);
for(int i=0;i<n;i++){
System.out.println(arr[i]);
}
//System.out.println(arr);
}
}
但是这样就没问题了吗?当然不是我们这里是讲arr的长度设置的比文件中的字符个数要大因此才可以正常打印可是如果更小呢?如果更小的话很明显我们的代码时不行 的那么怎么办呢?这里就要讲解一下read的工作原理他的工作原理其实时讲文件中的内容尽可能的写到传入的数组中如果一次不行就多传几次因此我们可以加个while循环多次写入,并且当文件中的内容全部写到了数组中之后就会返回-1。代码如下
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class test_byte {
public static void main(String[] args) throws IOException {
Reader reader=new FileReader("d:/test.txt");
char[] arr=new char[2];
while(true){
int n=reader.read(arr);
if(n==-1){
break;
}
for(int i=0;i<n;i++){
System.out.println(arr[i]);
}
}
//System.out.println(arr);
}
}
那么如何写入呢?其实跟上面的方式是差别不大的。我们直接来看看代码就可以了。
import java.io.*;
public class test_byte {
public static void main(String[] args) throws IOException {
Writer writer=new FileWriter("d:/test.txt");
String string=new String("JAVA你好");
writer.write(string);
writer.flush();
//System.out.println(arr);
}
}
这里可能会有困惑的地方应该就是flush这里,那么为什么要加个flush呢?其实是因为我们在进行写的时候其实不是直接写进文件中的而是先写进一个缓冲区里,这是为什么呢?
我们可以想一下一个人嗑瓜子,那么这个人嗑瓜子需要扔瓜子皮,垃圾桶此时又不在他身边,那么这时候他是磕一个瓜子然后去扔一个瓜子皮方便呢?还是把嗑下来的瓜子皮先用纸巾包着然后嗑够了后再去把这些嗑下的瓜子皮一下子全扔掉更好呢?很明显是第二种更好,此时这个纸巾其实就是缓冲区,那么如何告诉缓冲区我已经写好了赶紧把缓冲区中的数据刷新到内存中把,很简单其实就是用这个flush方法。
警告
但是上面的代码是一个有很严重bug那就是当我们进行读写操作后没有进行close,这是一个很严重的问题,我们在进行文件操作的时候必须要进行close,因为我们打开的文件其实都有一个数字去代表这个文件而这个数字时保存在了一个顺序表中的,这个顺序表如果被占满的话就会导致代码崩溃。那么为了防止这样的事件发生我们有什么办法呢?有的那就是将我们实例化出的对象放在try的小括号中
import java.io.*;
public class test_char {
public static void main(String[] args) throws FileNotFoundException {
try(Reader reader=new FileReader("d:/test.txt")){
char[] arr=new char[1024];
reader.read(arr);
System.out.println(arr);
}catch (IOException e){
e.printStackTrace();
}
}
}
字节流操作API
首先是字节流的类是什么呢?字节流的类有两个一个是InputStream,还有一个是OutputStream关于这两个类我们的分析如下
InputStream
import java.io.*;
public class test_char {
public static void main(String[] args) throws FileNotFoundException {
try(InputStream inputStream=new FileInputStream("d:/test.txt")) {
byte[]arr=new byte[1024];
int n=inputStream.read(arr);
for(int i=0;i<n;i++){
System.out.printf("%x ",arr[i]);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
那么此时的n就是这个文件中的字节数,而输出的数字就是这个文件中每个字符的ASCII码
此外呢我们读取文件还有一个办法那就是使用scanner代码如下
import java.io.*;
import java.util.Scanner;
public class test_char {
public static void main(String[] args) throws FileNotFoundException {
// try(OutputStream outputStream=new FileOutputStream("d:/test.txt")){
// String s="你好IO";
// outputStream.write(s.getBytes());
// }catch (IOException e){
// e.printStackTrace();
// }
try (InputStream inputStream=new FileInputStream("d:/test.txt")){
Scanner scanner=new Scanner(inputStream);
String s=scanner.nextLine();
System.out.println(s);
}catch (IOException e){
e.printStackTrace();
}
}
}
在这里呢我们的scanner初始化的时候传入我们的字节流对象即可完成。
OutputStream
那么如何向文件中写呢?那就是用outputStream这个类使用方法和上面其实大同小异
import java.io.*;
public class test_char {
public static void main(String[] args) throws FileNotFoundException {
try(OutputStream outputStream=new FileOutputStream("d:/test.txt")){
String s="你好IO";
outputStream.write(s.getBytes());
}catch (IOException e){
e.printStackTrace();
}
}
}
这里我们要注意几点那就是因为我们此时时字节流,因此我们输入按道理来说也得是字节流但是因为我们无法去记住每个字符他的ASCII码因此java中边封装了getBytes()因此我们在写入的时候需要调用这个方法将我们想要写的内容转化为字节码。
当然除此之外还有没有别的办法呢?当然也有。代码如下
import java.io.*;
import java.util.Scanner;
public class test_char {
public static void main(String[] args) throws FileNotFoundException {
try(OutputStream outputStream=new FileOutputStream("d:/test.txt")){
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.print("我爱你");
printWriter.flush();
}catch (IOException e){
e.printStackTrace();
}
// try (InputStream inputStream=new FileInputStream("d:/test.txt")){
// Scanner scanner=new Scanner(inputStream);
// String s=scanner.nextLine();
// System.out.println(s);
// }catch (IOException e){
// e.printStackTrace();
// }
}
}
我们只需要创建一个PrintWriter 然后再new的时候将OutputStream 对象传进去就可以完成字节流向字符流的转换了。
想要和你并肩看夕阳我心之所向。