和C,C++一样,java也有对应的文件操作,相比而言Java的文件操作比较简单,基本使用方法如下:
//定义File类
new File f1=new File("E://tempJaveFileDir");
new File f2=new File(f1,"/test.txt");
new File f3=new File("E://testJavaFileDir","/test.cpp");
//实例化创建文件目录或者文件夹
f.makeDirs();//创建多级路径,既能够创建父级目录
f.mkdir();//创建最后的一级目录
f.createNewFile();//创建出对应的文件
//说明:使用创建目录的方法,即使看起来是个文件但是也是可以成立的,比如创建一个test.txt目录是可行的。
//如果创建有一个目录,那么创建一个与之相同路径的同名文件是不可行的
//文件实例化都返回boolean数据,创建成功返回true,失败false.
//基本的检测方法
isDirectory();//检测是否是一个目录
isFile();//检测是否是一个文件
getAbsolutePath();//获取绝对路径
getPath();//返回创建时候使用的路径,如果是使用了相对路径则返回相对路径,使用绝对路径会返回绝对路劲
getName();//获取创建的file名
list();//返回当前给定的file目录下面的一级文件或者目录的路径(String类型)
listFiles();//返回当前给定的file目录下的file类型数组
delete();//删除文件,哈哈哈是不是想着: new File("E://").delete(),这是不行的。
//delete规定只有当下级目录是该分支的最后一级目录才能完成删除。
简单写个两个例子:
//模拟的其实是cmd下面的dir功能
String[] arrList=f.list();
File[] testList=f.listFiles();
for(File item:testList){
System.out.println("输出File绝对路径:"+item.getAbsolutePath());
}
//另外需要注意list与listFiles方法,如果当前目录没有下一级文件会报NullPointerException异常
//递归遍历文件
public static void getFile(File file){
File[] temp=file.listFiles();
if(temp!=null){
for(File item:temp){
if(item.isDirectory()){
getFile(item);
}else{
System.out.println("输出文件路径:"+file.getAbsolutePath());
}
}
}
}
public static void main(String[] args) {
File file=new File("E://JavaFileTest");
getFile(file);
}
2.基本流对象
类似于C++的流的概念,流只是数据传输的中间态的描述,文件含有输入流和输出流。一般来说分为字符流和字节流,其区分方法就是,字符流的字符的独立性较强,使用记事本打开能够读懂里面的内容,字节流整体性较强,记事本打开通常乱码。另外,需要注意的是字节流相对更加全面一些,被称为万能流。
文件输出流对象继承于OutputStream类,文件输入流对象继承于InputStream类,文件流的基本使用方法如下:
public static void main(String[] args) throws IOException {
FileOutputStream file=new FileOutputStream(new File("./test.txt"));
//首先创建了一个字符流需要操作的目标文件,这里的FileOutputStream中包含多个构造函数,
//当参数是String的时候,FileOutputStream首先会根据给定的String创建对应路径的文件,
//然后将让字符流指向得到的文件,之后进行写入操作
//异常说明:这里可能给定的String不能创建路径,或者使用write方法因为权限等原因没有写入成功。
}
file.write(97);
//注意这里支持三种不同的写法
write(byte)//字节
write(byte[])//字节数组
write(byte[] ,int off,byte.length)//字节数组,偏移量,长度(后面的两个参数是Byte数组里面的偏移量和长度)
注意一下写法快速创建内容:
byte [] str="testData".getBytes(); file.write(str,2,4);//stDa
和C++一样,最后加一个close()关闭流的目标文件以示友好:
file.close();
文件写入的异常处理终极版(这样写健壮性比较好,但是为了减少代码行数还是使用方法签名抛出异常):
public static void main(String[] args) {
FileOutputStream file= null;
try {
file = new FileOutputStream(new File("Z://test.txt"));//创建文件检测异常,保证文件创建成功
try {
byte [] str="testData".getBytes();
file.write(str,2,4);//文件读写异常检测
} catch (IOException e) {
e.printStackTrace();
}
finally {//无论是否异常都会被执行就如同Javascript里面的success,fail,compelete一样
try {
file.close();//文件关闭异常
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
文件流整体上分为基本字符流、缓冲字符流、基本字节流和缓冲字节流四部分,其用法大致类似,以基本字节流为例,给出数据读写的基本方法:
//逐一字符读写
FileInputStream file= new FileInputStream(new File("./test.txt"));
int data;
while((data=file.read())!=-1){//当读取到结尾后返回的是-1
System.out.print((char)data);
}
//指定每次读写的长度
FileInputStream file= new FileInputStream(new File("./test.txt"));
byte [] by=new byte[100];//指定每次读取的长度
int len;
while((len=file.read(by))!=-1){//这里每次读写会读取一个byte数组长度的空间,
//如果没有则会重用上一次的字符或者直接使用为空乱码填充,读取完成之后会返回一个长度,
//该长度等价于在目标源中取得的字符个数,如果没有获取到任何有用字符,直接返回-1;
System.out.println(new String(by,0,len));
}
为了更好的说明这个读取特点,给出如下例子:
byte [] by=new byte[5];
int index=1;
while((file.read(by))!=-1){
System.out.println("输出第"+index+"读取的数据:"+new String(by));
index++;
}
给出解释:和上面说的一样,只是这个使用的是windows11,在windows系统中读取字符一个回车会被解释成rn(被视为两个字符,r表示的是将光标移到首行,n表示光标移到下一格),对于mac回车被解释成r,Linux解释为n,因此最后读取的其实是【avarn】。
说完了简单的字节流使用,接下来说一下字符流的特点,字符流=字节流+编码表。这里首先说一下用法再来说这个编码表:
OutputStreamWriter writer=new OutputStreamWriter(new FileOutputStream("./test.txt"));
//说明:字符流对象的构造函数中需要含有流对象参数。
//OutputStreamWriter对应FileOutputStream,InputStreamReader对应FileInputStream,
char[] charArr={'h','e','l','l','o',' ','W','o','r','l','d'};
String str="Just do this!";
writer.write(charArr,0,5);//利用char输入写入,同时规定取值范围
writer.write(charArr);//利用char输入写入
writer.write(str);//利用字符串写入
writer.write(str,0,4);//利用字符串写入同时规定取值范围
writer.flush();//注意这个是必要的,用来刷新文件,
//附:close()中也含有flush()方法
字符输入流的写法可以说是和字符输出流完全一致了:
InputStreamReader reader=new InputStreamReader(new FileInputStream("./test.txt"));
char [] by=new char[5];//需要注意的是这里使用的是char类型
int len;
while((len=reader.read(by))!=-1){
System.out.print(new String(by,0,len));
}
3.编码集
接下来说一下基本的编码集概念,都学到Java了自然不能像C语言时候那么草率了。其实对于信息本质都是通过01进行存储的,只是通过具体的编码级进行了解码(编码:将通常我们能够认识的信息转化成及其容易存储的01数据,解码:将计算机中存储的01数据读取并转化成我们能够识别的信息)。
字符编码集(简称字符集)其实就是二者的桥梁。最开始使用的是我们熟悉的ASCII码,它是基于拉丁字母的编码集,用于显示英文字母及其相关字符(如标点和阿拉比数字等)。起初是7位表示一个字符,之后改用8位表示一个字符,方便支持欧洲常用字符。然而,就像大家看到的中文乱码一样,这套编码集不支持中文,于是当中国计算机发展到了一定阶段,出现了中文字符集GB2312,在原来8字节表示一个字符的基础上进行演化,如果连续的两个字符值都大于127,那么将这两个字符识别为一个汉字,最终整合了7000多个汉字以及相关数学符号和希腊字母。后来经过迭代出现了GBK,在GB2312的基础上做了一些扩展,直接使用双字节编码,收录了20000多个汉字,支持繁体和日韩文字等。最后考虑到中国存在一些少数名族语言,推出了GB18030,收录70000多个文字,每个文字可以有1个、2个或者4个字节表示。
当然,这还不是编码集到这里还是不够的,如今使用最多的是Unicode字符集,是一种全世界都能够使用的编码集,最多使用4个字节来表达字母、符号或者文字,一共有三种编码方式:UTF-8、UTF-16、UTF-32。其中使用最多的是UTF-8,,在网络的邮件传输、存储等都优先使用这种字符集。一般而言,128个US-ASCII字符使用1个字节,拉丁文等使用2个字节,大多数常用字(含中文等)使用3个字节,极少数文字使用4个字节。
4.缓冲流对象 文件流对象除了上面提到的流对象外,还有一类缓冲流对象。缓冲流对象相比基本的流对象对于数据的处理要更快一些,基本使用方法如下(整体上和基本流对象的使用方法一致):
//文件缓冲流对象参照文件流对象的用法
BufferedOutputStream writer=new BufferedOutputStream(new FileOutputStream("./test.txt"));
writer.write("hello world".getBytes());//多字符的写入
writer.flush();//缓冲流对象需要刷新缓冲区
BufferedInputStream reader=new BufferedInputStream(new FileInputStream("./test.txt"));
byte [] by=new byte[5];//多字符读取
int len;
while((len=reader.read(by))!=-1){
System.out.print(new String(by,0,len));
}
//字符缓冲流对象参照字符流对象的用法
BufferedWriter writer=new BufferedWriter(new FileWriter("./test.txt"));
writer.write("hello java");//利用String写入
writer.flush();//缓冲流对象需要刷新缓冲区
BufferedReader reader=new BufferedReader(new FileReader("./test.txt"));
char [] ch=new char[5];//多字符读取
int len;
while((len=reader.read(ch))!=-1){
System.out.print(new String(ch));
}
最后写一个案例说明一下这里的数据的类型可以是对象,不仅仅是基本类型:
public static void main(String[] args) throws IOException {
//集合-》文件
ArrayList studentList=new ArrayList<>();
studentList.add(new Student("张三",19));
studentList.add(new Student("李四",20));
studentList.add(new Student("王五",18));
BufferedOutputStream writer=new BufferedOutputStream(new FileOutputStream("./test.txt"));
for(Student item:studentList){
writer.write(item.swichToString().getBytes());
writer.write('n');
}
writer.flush();
//文件-》集合
ArrayList getList=new ArrayList<>();
BufferedReader reader=new BufferedReader(new FileReader("./test.txt"));
String line;
while((line=reader.readLine())!=null){//readLine是bufferReader的特有方法
String [] values=line.split(" ");
getList.add(new Student(values[0], Integer.parseInt(values[1])));
}
System.out.println("输出读取内容");
for(Student item : getList){
System.out.println("输出学生数据:"+item.name+" "+item.age);
}
writer.close();
}
到这里,可能这便是我C语言结束的地方,也标志着我开始熟悉了Java语言,是梦开始的地方。
Java,凌空暗羽来了!



