我的数据存储在存储在txt文件中的大型矩阵中,这些文件包含数百万行和4列逗号分隔值。 (每列存储一个不同的变量,每行存储所有四个变量的不同毫秒数据。)在前十几行中也有一些不相关的标题数据。我需要编写Java代码将这些数据加载到四个数组中,txt矩阵中的每一列都有一个数组。 Java代码还需要能够判断标头何时完成,以便第一个数据行可以拆分为4个数组的条目。最后,java代码需要遍历数百万个数据行,重复将每行分解为四个数字的过程,每个数字都输入到数字所在列的相应数组中。
有人可以告诉我如何改变下面的代码来实现这个目标吗?
我想找到完成数百万行处理的最快方法。这是我的代码:
MainClass2.java
package packages;
public class MainClass2{
public static void main(String[] args){
readfile2 r = new readfile2();
r.openFile();
int x1Count = r.readFile();
r.populateArray(x1Count);
r.closeFile();
}
}
readfile2.java
package packages;
import java.io.*;
import java.util.*;
public class readfile2 {
private Scanner scan1;
private Scanner scan2;
public void openFile(){
try{
scan1 = new Scanner(new File("C:\\test\\samedatafile.txt"));
scan1 = new Scanner(new File("C:\\test\\samedatafile.txt"));
}
catch(Exception e){
System.out.println("could not find file");
}
}
public int readFile(){
int scan1Count = 0;
while(scan1.hasNext()){
scan1.next();
scan1Count += 1;
}
return scan1Count;
}
public double[] populateArray(int scan1Count){
double[] outputArray1 = new double[scan1Count];
double[] outputArray2 = new double[scan1Count];
double[] outputArray3 = new double[scan1Count];
double[] outputArray4 = new double[scan1Count];
int i = 0;
while(scan2.hasNext()){
//what code do I write here to:
// 1.) identify the start of my time series rows after the end of the header rows (e.g. row starts with a number AT LEAST 4 digits in length.)
// 2.) split each time series row's data into a separate new entry for each of the 4 output arrays
i++;
}
return outputArray1, outputArray2, outputArray3, outputArray4;
}
public void closeFile(){
scan1.close();
scan2.close();
}
}
以下是典型数据文件的前19行:
text and numbers on first line
1 msec/sample
3 channels
ECG
Volts
Z_Hamming_0_05_LPF
Ohms
dz/dt
Volts
min,CH2,CH4,CH41,
,3087747,3087747,3087747,
0,-0.0518799,17.0624,0,
1.66667E-05,-0.0509644,17.0624,-0.00288295,
3.33333E-05,-0.0497437,17.0624,-0.00983428,
5E-05,-0.0482178,17.0624,-0.0161573,
6.66667E-05,-0.0466919,17.0624,-0.0204402,
8.33333E-05,-0.0448608,17.0624,-0.0213986,
0.0001,-0.0427246,17.0624,-0.0207532,
0.000116667,-0.0405884,17.0624,-0.0229672,
修改
我测试了Shilaghae的代码建议。它似乎工作。但是,所有结果数组的长度与x1Count相同,因此零位保留在Shilaghae的模式匹配代码无法放置数字的位置。 (这是我最初编写代码的结果。)
我很难找到零保留的索引,但除了标题所在的那些之外,似乎还有更多的零。当我绘制temp [1]输出的导数时,我看到了一些尖锐的尖峰,其中temp [1]中的假零点可能是。如果我可以告诉temp [1],temp [2]和temp [3]中的零点,我可以修改模式匹配以更好地保留所有数据。
此外,简单地将输出数组缩短为不再包含标题位于输入文件中的行将是一件好事。但是,我发现的关于可变长度数组的教程只显示了过于简单的示例,如:
int[] anArray = {100, 200, 300, 400};
如果代码不再使用scan1生成scan1Count,代码可能运行得更快。我不想通过使用低效方法来生成可变长度数组来减慢代码速度。在模式匹配无法将输入行拆分为4个数字的情况下,我也不想跳过时间序列中的数据。我宁愿保留及时序列中的零,以便我可以找到它们并使用它们来调试模式匹配。
有人能说明如何在快速运行的代码中执行这些操作吗?
所以
"-{0,1}\\d+.\\d+,"
在表达式中重复一次:
"-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,"
"-{0,1}\\d+.\\d+,"
分解为以下三个陈述:
"-{0,1}" means that a minus sign occurs zero or one times, while
"\\d+." means that the minus sign(or lack of minus sign) is followed by several digits of any value followed by a decimal point, so that finally
"\\d+," means that the decimal point is followed by several digits of any value?
如果是这样,我的数据中的数字如“1.66667E-05”或“-8.06131E-05”怎么样?我刚刚扫描了一个输入文件,并且(在3百多万个4列行中)它包含638个包含E的数字,其中5个在第一列,633在最后一列。
最终代码非常简单,只需使用带有“,”的string.split()作为正则表达式。为此,我不得不手动删除输入文件中的标题,以便数据只包含4个逗号分隔数字的行。
如果有人好奇,最终的工作代码是:
public double[][] populateArray(int scan1Count){
double[] outputArray1 = new double[scan1Count];
double[] outputArray2 = new double[scan1Count];
double[] outputArray3 = new double[scan1Count];
double[] outputArray4 = new double[scan1Count];
try {
File tempfile = new File("C:\\test\\mydatafile.txt");
FileInputStream fis = new FileInputStream(tempfile);
DataInputStream in = new DataInputStream(fis);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
int i = 0;
while ((strLine = br.readLine()) != null) {
String[] split = strLine.split(",");
outputArray1[i] = Double.parseDouble(split[0]);
outputArray2[i] = Double.parseDouble(split[1]);
outputArray3[i] = Double.parseDouble(split[2]);
outputArray4[i] = Double.parseDouble(split[3]);
i++;
}
} catch (IOException e) {
System.out.println("e for exception is:"+e);
e.printStackTrace();
}
double[][] temp = new double[4][];
temp[0]= outputArray1;
temp[1]= outputArray2;
temp[2]= outputArray3;
temp[3]= outputArray4;
return temp;
}
感谢大家的帮助。我现在要关闭这个帖子,因为问题已得到解答。
答案 0 :(得分:1)
如果行正好显示4个逗号,您可以使用正则表达式(http://www.vogella.de/articles/JavaRegularExpressions/article.html)读取行到行文件以及您可以控制的每行。 如果该行恰好是4个逗号,则可以使用String.split拆分该行并填充4个数组,否则您将在下一行传递。
public double[][] populateArray(int scan1Count){
double[] outputArray1 = new double[scan1Count];
double[] outputArray2 = new double[scan1Count];
double[] outputArray3 = new double[scan1Count];
double[] outputArray4 = new double[scan1Count];
//Read File Line By Line
try {
File tempfile = new File("samedatafile.txt");
FileInputStream fis = new FileInputStream(tempfile);
DataInputStream in = new DataInputStream(fis);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
int i = 0;
while ((strLine = br.readLine()) != null) {
Pattern pattern = Pattern.compile("-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,");
Matcher matcher = pattern.matcher(strLine);
if (matcher.matches()){
String[] split = strLine.split(",");
outputArray1[i] = Double.parseDouble(split[0]);
outputArray2[i] = Double.parseDouble(split[1]);
outputArray3[i] = Double.parseDouble(split[2]);
outputArray4[i] = Double.parseDouble(split[3]);
}
i++;
}
} catch (IOException e) {
e.printStackTrace();
}
double[][] temp = new double[4][];
temp[0]= outputArray1;
temp[1]= outputArray2;
temp[2]= outputArray3;
temp[3]= outputArray4;
return temp;
}
答案 1 :(得分:0)
您可以使用String.split()拆分每一行。
要跳过标题,您可以读取前N行并丢弃它们(如果您知道有多少行),或者您需要查找特定标记 - 很难在不查看数据的情况下提供建议。
你可能还需要稍微改变你的方法,因为你现在似乎是根据行总数(假设你的扫描仪返回行?)来调整数组的大小,而不是省略标题行的数量。
答案 2 :(得分:0)
我只是尝试将每个行解析为四个数字,并丢弃解析不起作用的任何行,从而解决标题问题。如果标题行之后有可能出现不可解析的行,那么您可以在第一次获得“良好”行时设置标记,然后报告任何后续“坏”行。
用String.split(...)
分割线条。这不是绝对最快的方法,但程序的CPU时间将用于其他地方......所以它可能并不重要。