1.文件的路径
如图:

当我们打开此电脑后(windows系统),上面会显示我们当前的位置,点击之后会出现如图片中的一段字符,这段字符代表着当前你所处位置的路径。
最开头的D:/d:是盘符,后面会用斜杠‘/’或者反斜杠‘\’分开,该符号用来是分割目录的,如图,此时ccc文件处于d盘中的aaa文件中的bbb文件里。
我们表示路径有两种风格:
(1)绝对路径:以c:/d:等开头的路径,如图片中的;
(2)相对路径:以当前的路径为基准,以.或者..为开头(.有时候可以忽略)
绝对路径很好理解,那么相对路径是怎么表示的呢?
相对路径的表示方法是:以.或者..作为开头。
以.为开头表示当前文件所处的位置,在上面的图片中./就代表d:/aaa/bbb/
../表示当前文件的前面一个文件,在上面的图片中../表示d:/aaa/
如果想再往前一个文件就再加一个../,上面图片中../../就表示d:/
2.文件的类型
在电脑中可以存储各种各样的文件,比如:视频、音频、图片、txt、exe....
这些不同的文件可以归纳为两大类:文本文件和二进制文件
文本文件:存储的是文本/字符串,字符串是由字符构成的,这个文本里面存的数据,一定都是合法字符,都是在你指定编码表之内的数据。
二进制文件:存放的是二进制数据(不一定是字符串了),这种文件没有任何限制,可以存储你想要的任何类型的数据
如果想区分你电脑中的文件是二进制文件还是文本文件,那么可以使用记事本打开,如果里面是一堆乱码那么即使二进制文件,反之则是文本文件。
3.Java中对于文件的操作
3.1 针对文件的系统操作
这部分操作包括:删除文件、创建文件、重命名等
在Java中提供了一个File类。
这个类有三个构造方法:
(1)File(File parent,String child) 通过父路径+子路径合并成一个新的File实例
(2)File(String pathname)直接输入路径,根据输入的路径创建出一个File实例(路径可以是绝对路径或相对路径)
(3)File(String parent,String child)通过父目录+孩子目录创建出一个新实例
除了构造方法之外,它还有很多简单方便的方法来完成文件的系统操作
下面用代码演示(idea上面的当前文件所在位置就是当前项目所在的位置)
(1)查看文件路径信息
public static void main(String[] args) throws IOException {
//传入的 目录或文件 可以是不存在的 目录或文件
File file = new File("./test.txt");
System.out.println(file.getName());//返回名称
System.out.println(file.getParent());//返回父目录文件路径
System.out.println(file.getPath());//返回文件路径
System.out.println(file.getAbsolutePath());//返回绝对路径
System.out.println(file.getCanonicalPath());//返回修饰过的绝对路径
}
(2)创建文件和查询文件信息
public static void main(String[] args) throws IOException {
File file = new File("./test.txt");
file.createNewFile();//自动创建一个空文件,返回true
System.out.println(file.exists());//判断文件是否存在
System.out.println(file.isFile());//判断文件是否是一个普通文件
System.out.println(file.isDirectory());//判断文件是否是目录
}
(3)删除文件
public static void main(String[] args) {
File file = new File("./test.txt");
file.delete();//删除文件,返回true
file.deleteOnExit();//也是删除文件,但是不会立即删除,会在程序退出时进行删除
}
(4)创建目录
运行前没有test等文件
public static void main(String[] args) {
File file = new File("./test/aaa/bbb/");
//file.mkdir();//只能创建一级目录
file.mkdirs();//可以创建多级目录
}

如果用mkdir会创建失败,如果只有一级目录比如./test就可以成功创建
(5)重命名
public static void main(String[] args) {
File file = new File("./test");
File dest = new File("./testAAA");
file.renameTo(dest);//重命名 里面传入一个file对象
}

3.2 针对文件的内容操作
3.2.1 流对象
对于文件的内容操作是通过流对象来完成的。
流对象的流代表什么意思呢?
流代指水流,生生不息,随心所欲
假如,有一个文件,里面有100字节的数据
此时我可以选择一次读完100字节的数据,也可以选择每次读20字节的数据分5次读完......
所以将有关读写的对象成为“流对象”
Java标准库的流对象可以分为两大类
(1)字节流 操作二进制数据
InputStream FileInputStream
OutputStream FileOutputStream
(2)字符流 操作文本数据
Reader FileReader
Writer FileWriter
上述不带File开头的类 都是抽象类,不可以被实例化,在实例化时要实例化与其对应的File开头的类
3.2.2 字节流
以字节为单位去读写数据
InputStream类 -- 读
在创建实例时,在参数处可以选择用字符串的方式传入文件的位置,也可以传入一个InputStream对象,在其自己的构造方法中去接收里面的文件位置
public static void main(String[] args) throws IOException {
//创建InputStream的时候要用FileInputStream,参数可以使用绝对路径,也可以使用相对路径
InputStream inputStream = new FileInputStream("d:/test.txt");
//无参数版本
/*while(true) {
int b = inputStream.read();
if(b == -1) {
//读到 -1 说明读完了
break;
}
System.out.printf("%x \n", (byte)b);
}*/
//
while(true) {
//buffer -- 缓冲区 提高IO的效率
byte[] buffer = new byte[1024];
int len = inputStream.read(buffer);
for(int i = 0; i < len; i++) {
System.out.printf("%x \n",buffer[i]);
}
if(len == -1) {
break;
}
}
inputStream.close();
}
InputStream类中读取文件内容的方法为read
read如果无参数,那么会返回一个字节的数据
read里面传入一个byte数组,每次会根据这个数组的容量,将数据放到数组中,如果数据不足,则能放到哪里就放到哪里
read里面传入一个数组、一个起始下标、一个获取的长度,会将数据存放到数组指定的位置
read的返回类型是int,它会返回读取文件数据的个数,如果读取不到数据会返回-1。
OutputStream -- 写
和InputStream类似,只有使用的方法不同
写操作使用的方法为write
注意:写操作会先将文件里面的内容情况,再进行写操作
write中可以传入一个整形,byte数组,byte数组、起始下标、需要传入的长度
public static void main(String[] args) throws IOException {
OutputStream outputStream = new FileOutputStream("d:/test.txt");
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
outputStream.close();
}
3.2.3 close操作
在进程中,有一个文件描述符表,它是一个数组,里面存放的是该进程打开了哪些文件(进程里面的线程都公用一个),并且这个数组是固定大小,不会进行扩容操作,每次打开一个文件就会将这个信息存放进去,当进行close操作后,会将相对应的信息删除掉,如果使用完毕后不去进行close操作,就可能导致数组被填满,此时再想打开文件就会打开失败。
虽然在Java有GC会进行回收工作,但是GC操作并不一定及时,还是有可能会导致表被填满。
如果一个被进程结束,那么其相对应的资源也会被回收掉,所以,如果进行完close之后程序就结束了,此时不进行close也是可以的
但是有的时候close可能会执行不到(按照上面的代码),那么仍然会出现表被填满的问题,那么如何让close一定被执行到呢?
可以使用try(),如下:
public static void main(String[] args) throws IOException {
//下面的代码可以确保close被执行到 只要try语句执行完毕,就会自动执行close
//如果想通过try()去自动关闭 要求类中实现了Closeable接口
try(OutputStream outputStream = new FileOutputStream("d:/test.txt")) {
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);
outputStream.write(101);
}
}
3.2.4 字符流
和字节流基本相同,下面直接给出代码
Reader -- 读
public static void main(String[] args) throws IOException {
try(Reader reader = new FileReader("d:/test.txt")) {
while(true) {
int ret = reader.read();
if(ret == -1) {
break;
}
System.out.printf("%c \n",ret);
}
}
}
Writer -- 写
写操作相对于字节流,可以传入字符串
public static void main(String[] args) {
try(Writer writer = new FileWriter("d:/test.txt")) {
writer.write('a');
writer.write('b');
writer.write('c');
writer.write('d');
writer.write("abcd");
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
3.2.5 Scanner和流对象
Scanner是可以搭配流对象去使用的
通常我们使用Scanner都是使用其进行输入操作,在参数处会添加System.in
如果我们去查看in的原码,会发现它就是一个InputStream对象,那么我们就完全可以自己传入一个InputStream对象再使用Scanner去读取里面的数据,如下:
public static void main(String[] args) throws FileNotFoundException {
try(InputStream inputStream = new FileInputStream("d:/test.txt")) {
Scanner scanner = new Scanner(inputStream);
//此时可以从 inputStream 的文件中读取数据
String ret = scanner.next();
System.out.println(ret);
} catch (IOException e) {
e.printStackTrace();
}
}