文件.硬盘.IO
一.文件
(1)文件本身是包含多种意义的,这里我简单的说明一下文件的意义。
(2) 狭义上的文件:我们在硬盘中的文件。文件夹(目录)中存放的是文件。
(3) 广义上的文件:计算机上的硬件设备、软件资源,在操作系统中都会被视为文件。(举例:输入设备:键盘,输出设备:控制台,打印机,网卡……)
二.文件系统
(1)文件系统介绍:
在一台电脑上存在许多文件,许多文件需要通过操作系统进行管理。操作系统中存在一个专属于文件的操作系统,“文件操作系统”。文件操作系统一般通过文件资源管理器这个程序,可以观察文件系统中管理的文件。文件资源管理器也就是电脑上名为此电脑的一个程序,这个程序以前也叫我的电脑,计算机,这台电脑,名字的话会不断变化但是其功能大致相同。
(2)路径引子:
点击此电脑之后,就会出现我们电脑上的硬盘个数,刚买的电脑一般都是一个硬盘,之后可能大部分人都会拿去分盘。
点击C盘进入之后就是许多的目录和文件。(文件目录的结构式N叉树的结构)
点击上面的目录其中又是目录和文件的结构,因此可以确定文件在硬盘上的准确位置。例如我这里的一个测试目录。
这里的一串目录结构就是文件所在的位置,这一串目录结构也叫完整的文件路径。文件路径的表示方式还可以是下图类型,其中的/是分割符,在Windows中/和\都可以作为分割符。
由此路径也可以认为是一个文件的一种身份标识,可以通过标识来区分唯一的一个文件。
(3)绝对路径:
从盘符开始,一直到文件名结束:C:\Users\测试\木火因,txt
(4)相对路径:
相对路径是需要一个“参考系”才能进行对文件的查找,“参考系”一般被叫做“基准路径”或“工作路径”。举个例子,找一个文件,此时这个文件的绝对路径是:C:\Users\Public\Documents\Foxit ContentPlatform\Cookie,当找到上一级的“基准路径”:C:\Users\Public\Documents\Foxit ContentPlatform,再通过.\Cookie就可以找到需要的文件了。(.\是当前路径,..\是返回上一级的路径)。或者当在C:\Users\Public\Documents这个“基准路径”的时候,可以通过.\Foxit\ContentPlatform\Cookie找到这个文件。(基准目录不同,相对路径也就不同)在写代码的时候一般使用的是相对路径查找文件,而一个文件的绝对路径只适合于你的电脑,每个人的电脑存放一个文件时会在不同的路径。
三.文件类型
(1)文本文件:
当前文件存储的所有内容,都是“文本”(合法的字符(合法的字符也就是字符的编码方式(字符集)中文就有 UTF8 / GBK,这些字符编码就是很大的“表格”))。即使文本文件也是通过二进制来进行存储的,但是这些二进制可以在“表格”中找到对应的字符。(.txt .c .java都是文本文件)
(2)二进制文件:
二进制文件也是用二进制进行存储的,只不过在字符集的“表格”中找不到对应的字符或者就是乱码,此时就是二进制文件。(.exe .dll .mp3 .mp4 .class word docx 二进制文件)
(3)区分文件类型的方法(简单粗暴)
通过记事本打开文件,看文件里面的内容是否为乱码,是的话就是二进制文件,不是的话为文本文件
二进制文件:
文本文件:
四.文件操作.IO
(1)文件系统操作:创建文件,删除文件,创建目录,重命名文件,判定文件是否存在...
在java中有专门的File类,进行文件系统的操作,这个对象,会使用路径进行初始化,从而表示一个具体的文件(该文件可以存在或者不存在)。基于File创建的对象来进行后续的操作。
(i)File类中的属性:
(ii)File类的构造方法:
(iii)方法:
(iv)方法使用:
(1·)getParent,getName,getPath,getAbsoluteFile,getCanonicalFile使用
(2·)exists,isFile,isDirectory的使用
(3·)delelete的使用
(4·)deleteOnExit :进程结束时删除文件,需要注意的是,当该进程没有结束的时候文件并没有被删除,只有当该进程结束,文件才会被删除,如下面两张图片:
(5·)deleleteOnExit使用
(6·)list和listFiles的使用
(7·)所有目录的所有文件:(使用递归)
(8·)mkdir和mkdirs的使用
(9·)renameTo(File dest):需要注意的是,当我们在修改文件的路径的时候,如果源文件路径写的是完整的路径,那么将其中一根路径转移则不会有他的子目录,如果像图中所写源文件路径,则转移文件后会带有子目录。
(2)文件内容操作:读文件,写文件。
在java中进行文件内容操作是通过系统提供的API 来进行使用的,java对此也进行了封装,为此称之为文件流或者IO流。而Java实现IO流的类有很多,分成两个大的类:字节流和字符流。其中字节流是二进制文件并且读写数据的基本单位是字节,字符流是文本文件并且读写数据的基本单位是字符。(需要注意的是,一个字符的大小是根据实际的编码方式,不同的编码方式,一个字符的字节数是不同的。并且字符流的内部工作会做的更多一点,它会自动查询码表,把二进制数据转换成对应的字符)。
(1·)字节流的抽象类是:inputStream和outputStream。
(1··)打开文件和关闭文件:
这里需要注意的是,使用InputStream会打开文件,并且打开文件之后,将在该进程的文件描述符表中,创建了一个新的表项。(文件描述符表:简单的可以理解是一个数组,对于Linux内核中来说的话,每一个元素是一个结构体,每个结构体对应的是这个文件的信息,数组的下表被称为文件描述符)因此当我们打开一个文件的时候,文件描述符表中就会占用其数组中的一个位置,并且这个数组是不会扩容的,是固定长度大小,那么如果我们不进行资源的释放,就会导致服务器的崩溃。后续文件的打开也就是创建新的文件信息就没办法成功了。这个问题称为资源泄露问题。故在使用InputStream时,需要通过close来关闭文件,不至于导致文件描述符表爆满。图一的写法比较臃肿,一般使用图二的写法,图二中也需要注意的是,要使用try括号那就必须这个类实现了Closeable接口;并且这种写法被叫做try withresource。并且括号里面创建的资源可以是多个。最重要的是,当try{}执行完毕时,会自动执行里面的close,就不必写finally。
(2··)读文件:
第一种方式:通过读调用一次read读一个字节。当返回的值为-1的时候代表读完了文件中的数据。这里频繁的读取硬盘,此时硬盘的IO是耗时比较大的,为此需要减少IO次数就需要使用到第二个方法。
第二种方式,通过一次性的IO把数据放在数组中。这里也是在循环中不断读取文本中的数据,当文本中的数据被读完,返回一个-1则退出循环。并且这里不同的是通过数组作为参数先传入read中,read中的数据就被放在了这个数组中,这种方式叫做输出型参数,这个方法进行的IO次数就会减少很多。
与第二种方法类似,只不过是将数据中读到的内容放在了[off,off+len)中了。
(3··)写文件:使用OutputStream默认会把之前的内容清空,可以在write后面写true变成追加模式:
写文件和读文件也是类似的,第一种方法也就是在参数中写入数据的ASCIII或者对应的字节码表来进行写入数据:
第二种方法也就是传入字节数组。
第三种方法:传入字节数组的同时增加了偏移量,需要注意的是,偏移量必须是正确的完整ASCIII或者对应的字节码表,如果不完整的话就会造成乱码,下图所示:
(2·)字符流的抽象类是:Writer(输出)和Reader(输入)。
由于InputStream和OutputStream读写数据是通过字节来操作的,当需要输入字符的时候,就需要人为手动的却分每个字符区分那几个字节是一个字符,还需要确保内容的完整输入。为此,引入了字符流。(字符流和字节流的用法差不太多)
(1·)读文件:
需要注意的是,utf8的中文是3个字节,而我们在这里是用char来接受一个中文,而char只有2个字节,所以这里java用的不是utf8的编码方式而是用Unicode的方式来进行编码的。
第一种方法:一次读一个字符。
第二种方法和第三种方法与InputStream一样,这里是展示第二种方法:输出型参数
(2·)写文件:
这里写文件的方法大致和上述的都差不多,就不在一一赘述了,只写一个没出现的方法:可以直接在write中直接写入字符串。(这里和上述的OutputStream一样,写入数据的时候默认会清空文件的内容,所以可以在后面加上true变成追加写)
五.硬盘
需要说硬盘的功能,可以通过与内存作对比。
(1)硬盘的存储空间更大,内存的存储空间比较小。
(2)硬盘的读写速度慢,内存读写的速度快。
(3)硬盘的成本比内存的成本会更低。
(4)硬盘能持久化存储数据,内存断电之后数据就丢失了。