最近做实验室项目,因为有过多长短类型不一的数组要保存交互,感觉JDBC实在是有些麻烦,所以尝试用文件形式做交互,但是也遇到了一些问题。
1、文件读写相关程序
1)新建文件
File f=new File(path);
if(!f.exists()){
f.createNewFile();
}
2)删除文件
if(f.exists()&&f.isFile()){
f.delete();
}3)bufferedreader读取
BufferedWriter br = new BufferedReader(new FileWriter(path));
String content;
content=br.readLine(); //每次读取一行,如有分隔符可以进行分割
content.trim().//去除头尾的空格
//如果每一行是存入以逗号分隔的数组,以转换为double类型数组为例
String[] strAry = str.split(",");
double[] ary = new double[strAry.length];
for(int i = 0; i < strAry.length; i++){
ary[i] = Double.parseDouble(strAry[i]);
}
//如果每行只是一个单独的double类型数,即
double result=Double.parseDouble(br.readLine());
//读取全部结束后记得关闭数组
br.close();
4)BufferedWriter写入
BufferedWriter bw = new BufferedWriter(new FileWriter(path));
bw.write(string+"\n");
bw.close();
5)几个注意点:
【1】BufferedWriter bw = new BufferedWriter(new FileWriter(path)); 这句话是直接新建文件,在执行这句话的时候新文件就已经生成好了。如果原本已有文件,会覆盖内容。
【2】这种写法保存的文件一般后缀为txt或dat
【3】由于先建立文件,再进行写入,因此再前后端交互时,就算用先删除文件再创建文件的方式,也没有办法保证前后端写入和读取文件不发生冲突。
2、类型转化相关程序
为了将String和其他类型变量,或其他类型数组的相互转化,需要定义一些类型转化的方法,具体如下:
public static int[] intStrToArray(String str) {
String[] strAry = str.split(",");
int[] ary = new int[strAry.length];
for(int i = 0; i < strAry.length; i++){
ary[i] = Integer.parseInt(strAry[i]);
} return
public static String[] strToArray(String str) {
String[] strAry = str.split(",");
return strAry;
}
public static double[] doubleStrToArray(String str) {
String[] strAry = str.split(",");
double[] ary = new double[strAry.length];
for(int i = 0; i < strAry.length; i++){
ary[i] = Double.parseDouble(strAry[i]);
}
return ary;
}
public static String arrayToString(int[] ary){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < ary.length; i++){
sb.append(ary[i]).append(",");
}
sb.deleteCharAt(sb.length() -1);
return sb.toString();
}
public static String arrayToString(double[] ary){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < ary.length; i++){
sb.append(ary[i]).append(",");
}
sb.deleteCharAt(sb.length() -1);
return sb.toString();
}
public static String arrayToString(String[] ary){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < ary.length; i++){
sb.append(ary[i]).append(",");
}
sb.deleteCharAt(sb.length() -1);
return sb.toString();
}
3、采用的方案及遇到的坑
设前端为A,后端为B,A给B的文件称为A*,B给A的文件成为B*,如果整个流程需要控制为A*生成,后端读取A*,B*生成,前端读取B*四个顺序执行的步骤,
1)尝试1:用增删文件A*,B*的方式
流程开始时,先删除老的A*,B*,后端是while循环,判断A*生成了就开始读并计算,计算后生成B*,而前端此时写了一句File f=new File(path_B*); while(!f.exists()); 即是通过while一直等在那里,等到B*文件生成,再进行读取。
尝试失败,原因是write时先生成了文件,才进行的写入,因此读取时刻很可能文件没有写完。
2) 尝试2,用判断文件修改时间的方式
和1)其实本质上是一样的,用一个语句不断读取文件修改时间,如果更新了,则进行读取操作,但是与1)一样会遇到冲突。
判断文件是否修改的方法:
public String modify_time_old="2018-00-00 10:24:21";
public String modify_time;
public boolean isModify(String filepath){
File f = new File(filepath);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(f.lastModified());
String info=new String();
modify_time = sdf.format(cal.getTime());
boolean ismod=(!modify_time.equals(modify_time_old));
modify_time_old = modify_time;
return ismod;
}
3)尝试3,新建一个文件,通过读写这个文件的内容专门控制流程。
例如包装好一个set_stage和get_stage的方法,就是用与读取文件中的内容(如1,2),然后流程如前述方法一样,用while控着,直到读取的内容变为所需要的内容。问题和1),2)中是一样的,前后端再while的时候都再同时读取文件,所以会出bug。
4)尝试4,专门设定一个文件或多个文件用作flag,只判断这个文件是否存在,用delete和create的方式来控制流程。f.exists()相当于flag置1,否则相当于置0。和前面三种方法的不同在于,并不需要在创建文件后再进行读写,即整个流程中都不需要打开这个文件,没有同时读写这一冲突存在。
这种方法还是很蠢...不过可以使用。
5)尝试5,用重命名的方式让一个文件先变名字,写入完成后再变回来...理论上听起来好像可以,实际上还是会报错,报文件占用冲突的错误,不可取。
6)尝试6,对1)进行改进,具体有两种方案
6.1 采用文件锁的方法,参考
保证同时只有一个进程可以拿到文件的锁,这个进程从而可以对文件做访问;而其它拿不到锁的进程要么选择被挂起等待,要么选择去做一些其它的事情
在1)的基础上,添加文件锁,等待到一个进程写入完成后另一个进程再
6.2 用file.exist的方式再加一个delay
读取程序判断到文件生成后,先不进行读取,加一个delay(问题就是delay时间不好控制)。保证文件写入完成后再进行读取。