我需要获取一个 CSV 文件并将其拆分为基于列 Header [JAVA] 的单独文件
I need to take a CSV file and split it into separate files based on Column Header [JAVA]
我是 Java 的新手,正在努力阅读 > 排序 > 导出 csv。我有一个 [X, Y, Z, Scalar 1, Scalar 2, Scalar 3, Scalar 4] 作为 headers 的 csv,需要分成 4 个 csv。实际文件有几千行这么短的例子:
[X,Y,Z, Sc1, Sc2, Sc3, Sc4]
[1,0,0, 5, 7, 9, 10]
[0,1,1, 6, 8, 4, 0]
[0,0,1, 3, 3, 8, 2]
我需要将源 csv 拆分为 4 个单独的 csv,其中包含一个标量值和 x、y、z 数据。
File 1 | File 2 | File 3 | File 4
----------------------------------------------------------
[Sc1, X,Y,Z] | [Sc2, X,Y,Z] | [Sc3, X,Y,Z] | [Sc4, X,Y,Z]
[5, 1,0,0] | [7, 1,0,0] | [9, 1,0,0] | [10, 1,0,0]
[6, 0,1,1] | [8, 0,1,1] | [4, 0,1,1] | [ 0, 0,1,1]
[3, 0,0,1] | [3, 0,0,1] | [8, 0,0,1] | [ 2, 0,0,1]
我目前正在使用 BufferedReader 读取数据,但我不确定读取后如何组织数据,或者这是否是一个好方法。
ArrayList<String> readFileFast (String expDir,String filename) {
String path = expDir + filename;
ArrayList<String> fileContents = new ArrayList<>();
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
while ((line = br.readLine()) != null) {
fileContents.add(line);
}
} catch (Exception e) {
SuperStackPrint(e);
}
return fileContents;
}
println(readFileFast(expDir, "/DELETEME.csv"));
任何有关如何正确执行此操作的见解都将不胜感激。
您将受益于使用专门读取和写入 CSV 文件的库。有几个可供选择,但在这里我将使用 OpenCSV.
如果您最终没有使用这个库,它至少可以为您提供一些关于您自己的方法的想法。
此外,在使用库时,我建议使用 Maven 或 Gradle 等工具来帮助管理它,因为这些工具会为您处理“依赖关系的依赖关系”——例如,OpenCSV库本身需要访问它使用的其他库。
对于 Maven,这是我的 POM 文件的 OpenCSV 依赖项:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.2</version>
</dependency>
方法:
创建一个 Java class(一个“bean”)来保存将从源 CSV 文件加载的数据。在我的示例中,这将被称为 SplitBean
。
使用此 class 创建 collection 个 object,其中 每个 object 包含CSV文件一行的数据.
遍历 collection 个 object 秒,将相关部分写入 4 个输出文件。
您可以选择遵循上述方法而不使用 OpenCSV 或类似的库。但是您将不得不自己编写更多与基本 CSV 操作相关的代码。你的情况,数据并不复杂,这样也不无道理。
无论哪种方式,我建议创建一个 class 来表示一行输入数据,然后在写入输出文件时处理此类 object 的列表。这将流程分成两个不同的步骤,并使用 Java object 来简化流程。
这里是 SplitBean
class:
import com.opencsv.bean.CsvBindByName;
public class SplitBean {
@CsvBindByName(column = "X")
private int x;
@CsvBindByName(column = "Y")
private int y;
@CsvBindByName(column = "Z")
private int z;
@CsvBindByName(column = "Sc1")
private int sc1;
@CsvBindByName(column = "Sc2")
private int sc2;
@CsvBindByName(column = "Sc3")
private int sc3;
@CsvBindByName(column = "Sc4")
private int sc4;
public static String[] getHeadingsOne() {
String[] s = { "Sc1", "X", "Y", "Z" };
return s;
}
public static String[] getHeadingsTwo() {
String[] s = { "Sc2", "X", "Y", "Z" };
return s;
}
public static String[] getHeadingsThree() {
String[] s = { "Sc3", "X", "Y", "Z" };
return s;
}
public static String[] getHeadingsFour() {
String[] s = { "Sc4", "X", "Y", "Z" };
return s;
}
public String[] getDataOne() {
String[] i = { String.valueOf(sc1), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public String[] getDataTwo() {
String[] i = { String.valueOf(sc2), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public String[] getDataThree() {
String[] i = { String.valueOf(sc3), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public String[] getDataFour() {
String[] i = { String.valueOf(sc4), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
public int getSc1() {
return sc1;
}
public void setSc1(int sc1) {
this.sc1 = sc1;
}
public int getSc2() {
return sc2;
}
public void setSc2(int sc2) {
this.sc2 = sc2;
}
public int getSc3() {
return sc3;
}
public void setSc3(int sc3) {
this.sc3 = sc3;
}
public int getSc4() {
return sc4;
}
public void setSc4(int sc4) {
this.sc4 = sc4;
}
}
此 class 使用 @CsvBindByName
注释将源 CSV 文件中的列标题名称映射到 class 本身的字段名称。您不需要这样做,但这是 OpenCSV 提供的一个方便的功能。
class 还包含处理 4 个不同输出文件(它们是输入文件数据的子集)的方法。
现在我们可以写一个单独的 doTheSplit()
方法来使用这个 class:
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import com.opencsv.CSVWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.FileWriter;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class SplitData {
public void doTheSplit() throws URISyntaxException, IOException,
CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
HeaderColumnNameMappingStrategy msIn = new HeaderColumnNameMappingStrategy();
msIn.setType(SplitBean.class);
Path path = Paths.get("C:/tmp/csvsplit/input.csv");
List<SplitBean> list;
// read the data from the input CSV file into our SplitBean list:
try ( Reader reader = Files.newBufferedReader(path)) {
CsvToBean cb = new CsvToBeanBuilder(reader)
.withMappingStrategy(msIn)
.build();
list = cb.parse();
int i = 1;
}
// set up 4 file writers:
try ( CSVWriter writer1 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output1.csv"));
CSVWriter writer2 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output2.csv"));
CSVWriter writer3 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output3.csv"));
CSVWriter writer4 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output4.csv"))) {
// first write the headers to each file (false = no quotes):
writer1.writeNext(SplitBean.getHeadingsOne(), false);
writer2.writeNext(SplitBean.getHeadingsTwo(), false);
writer3.writeNext(SplitBean.getHeadingsThree(), false);
writer4.writeNext(SplitBean.getHeadingsFour(), false);
// then write each row of data (false = no quotes):
for (SplitBean item : list) {
writer1.writeNext(item.getDataOne(), false);
writer2.writeNext(item.getDataTwo(), false);
writer3.writeNext(item.getDataThree(), false);
writer4.writeNext(item.getDataFour(), false);
}
}
}
}
此代码的第一部分填充 List<SplitBean> list
。输入电子表格中的每一行数据都有一个 splitBean object。 OpenCSV 会在幕后为您处理大部分工作。
然后,代码创建 4 个文件编写器,它们使用 OpenCSV CSVWriter
object,帮助处理将我们的数据格式化为有效的 CSV 行。
使用此代码,我们将列 headers 写入 4 个文件中的每一个。最后,我们遍历 collection 个 SplitBean
项,并将相关数据子集写入每个文件。
因此,对于这样的 CSV 输入文件:
X,Y,Z,Sc1,Sc2,Sc3,Sc4
1,0,0,5,7,9,10
0,1,1,6,8,4,0
0,0,1,3,3,8,2
我们最终得到了 4 个不同的输出文件。一个例子:
Sc1,X,Y,Z
5,1,0,0
6,0,1,1
3,0,0,1
附加说明:以这种方式使用 SplitBean
class 的一大优势是,如果您决定需要,您将拥有更大的灵活性执行更多数据转换 - 例如,过滤掉数据行,或以不同方式对数据进行排序。
我是 Java 的新手,正在努力阅读 > 排序 > 导出 csv。我有一个 [X, Y, Z, Scalar 1, Scalar 2, Scalar 3, Scalar 4] 作为 headers 的 csv,需要分成 4 个 csv。实际文件有几千行这么短的例子:
[X,Y,Z, Sc1, Sc2, Sc3, Sc4]
[1,0,0, 5, 7, 9, 10]
[0,1,1, 6, 8, 4, 0]
[0,0,1, 3, 3, 8, 2]
我需要将源 csv 拆分为 4 个单独的 csv,其中包含一个标量值和 x、y、z 数据。
File 1 | File 2 | File 3 | File 4
----------------------------------------------------------
[Sc1, X,Y,Z] | [Sc2, X,Y,Z] | [Sc3, X,Y,Z] | [Sc4, X,Y,Z]
[5, 1,0,0] | [7, 1,0,0] | [9, 1,0,0] | [10, 1,0,0]
[6, 0,1,1] | [8, 0,1,1] | [4, 0,1,1] | [ 0, 0,1,1]
[3, 0,0,1] | [3, 0,0,1] | [8, 0,0,1] | [ 2, 0,0,1]
我目前正在使用 BufferedReader 读取数据,但我不确定读取后如何组织数据,或者这是否是一个好方法。
ArrayList<String> readFileFast (String expDir,String filename) {
String path = expDir + filename;
ArrayList<String> fileContents = new ArrayList<>();
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
while ((line = br.readLine()) != null) {
fileContents.add(line);
}
} catch (Exception e) {
SuperStackPrint(e);
}
return fileContents;
}
println(readFileFast(expDir, "/DELETEME.csv"));
任何有关如何正确执行此操作的见解都将不胜感激。
您将受益于使用专门读取和写入 CSV 文件的库。有几个可供选择,但在这里我将使用 OpenCSV.
如果您最终没有使用这个库,它至少可以为您提供一些关于您自己的方法的想法。
此外,在使用库时,我建议使用 Maven 或 Gradle 等工具来帮助管理它,因为这些工具会为您处理“依赖关系的依赖关系”——例如,OpenCSV库本身需要访问它使用的其他库。
对于 Maven,这是我的 POM 文件的 OpenCSV 依赖项:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.2</version>
</dependency>
方法:
创建一个 Java class(一个“bean”)来保存将从源 CSV 文件加载的数据。在我的示例中,这将被称为
SplitBean
。使用此 class 创建 collection 个 object,其中 每个 object 包含CSV文件一行的数据.
遍历 collection 个 object 秒,将相关部分写入 4 个输出文件。
您可以选择遵循上述方法而不使用 OpenCSV 或类似的库。但是您将不得不自己编写更多与基本 CSV 操作相关的代码。你的情况,数据并不复杂,这样也不无道理。
无论哪种方式,我建议创建一个 class 来表示一行输入数据,然后在写入输出文件时处理此类 object 的列表。这将流程分成两个不同的步骤,并使用 Java object 来简化流程。
这里是 SplitBean
class:
import com.opencsv.bean.CsvBindByName;
public class SplitBean {
@CsvBindByName(column = "X")
private int x;
@CsvBindByName(column = "Y")
private int y;
@CsvBindByName(column = "Z")
private int z;
@CsvBindByName(column = "Sc1")
private int sc1;
@CsvBindByName(column = "Sc2")
private int sc2;
@CsvBindByName(column = "Sc3")
private int sc3;
@CsvBindByName(column = "Sc4")
private int sc4;
public static String[] getHeadingsOne() {
String[] s = { "Sc1", "X", "Y", "Z" };
return s;
}
public static String[] getHeadingsTwo() {
String[] s = { "Sc2", "X", "Y", "Z" };
return s;
}
public static String[] getHeadingsThree() {
String[] s = { "Sc3", "X", "Y", "Z" };
return s;
}
public static String[] getHeadingsFour() {
String[] s = { "Sc4", "X", "Y", "Z" };
return s;
}
public String[] getDataOne() {
String[] i = { String.valueOf(sc1), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public String[] getDataTwo() {
String[] i = { String.valueOf(sc2), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public String[] getDataThree() {
String[] i = { String.valueOf(sc3), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public String[] getDataFour() {
String[] i = { String.valueOf(sc4), String.valueOf(x),
String.valueOf(y), String.valueOf(z) };
return i;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
public int getSc1() {
return sc1;
}
public void setSc1(int sc1) {
this.sc1 = sc1;
}
public int getSc2() {
return sc2;
}
public void setSc2(int sc2) {
this.sc2 = sc2;
}
public int getSc3() {
return sc3;
}
public void setSc3(int sc3) {
this.sc3 = sc3;
}
public int getSc4() {
return sc4;
}
public void setSc4(int sc4) {
this.sc4 = sc4;
}
}
此 class 使用 @CsvBindByName
注释将源 CSV 文件中的列标题名称映射到 class 本身的字段名称。您不需要这样做,但这是 OpenCSV 提供的一个方便的功能。
class 还包含处理 4 个不同输出文件(它们是输入文件数据的子集)的方法。
现在我们可以写一个单独的 doTheSplit()
方法来使用这个 class:
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import com.opencsv.CSVWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.FileWriter;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class SplitData {
public void doTheSplit() throws URISyntaxException, IOException,
CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
HeaderColumnNameMappingStrategy msIn = new HeaderColumnNameMappingStrategy();
msIn.setType(SplitBean.class);
Path path = Paths.get("C:/tmp/csvsplit/input.csv");
List<SplitBean> list;
// read the data from the input CSV file into our SplitBean list:
try ( Reader reader = Files.newBufferedReader(path)) {
CsvToBean cb = new CsvToBeanBuilder(reader)
.withMappingStrategy(msIn)
.build();
list = cb.parse();
int i = 1;
}
// set up 4 file writers:
try ( CSVWriter writer1 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output1.csv"));
CSVWriter writer2 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output2.csv"));
CSVWriter writer3 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output3.csv"));
CSVWriter writer4 = new CSVWriter(new FileWriter("C:/tmp/csvsplit/output4.csv"))) {
// first write the headers to each file (false = no quotes):
writer1.writeNext(SplitBean.getHeadingsOne(), false);
writer2.writeNext(SplitBean.getHeadingsTwo(), false);
writer3.writeNext(SplitBean.getHeadingsThree(), false);
writer4.writeNext(SplitBean.getHeadingsFour(), false);
// then write each row of data (false = no quotes):
for (SplitBean item : list) {
writer1.writeNext(item.getDataOne(), false);
writer2.writeNext(item.getDataTwo(), false);
writer3.writeNext(item.getDataThree(), false);
writer4.writeNext(item.getDataFour(), false);
}
}
}
}
此代码的第一部分填充 List<SplitBean> list
。输入电子表格中的每一行数据都有一个 splitBean object。 OpenCSV 会在幕后为您处理大部分工作。
然后,代码创建 4 个文件编写器,它们使用 OpenCSV CSVWriter
object,帮助处理将我们的数据格式化为有效的 CSV 行。
使用此代码,我们将列 headers 写入 4 个文件中的每一个。最后,我们遍历 collection 个 SplitBean
项,并将相关数据子集写入每个文件。
因此,对于这样的 CSV 输入文件:
X,Y,Z,Sc1,Sc2,Sc3,Sc4
1,0,0,5,7,9,10
0,1,1,6,8,4,0
0,0,1,3,3,8,2
我们最终得到了 4 个不同的输出文件。一个例子:
Sc1,X,Y,Z
5,1,0,0
6,0,1,1
3,0,0,1
附加说明:以这种方式使用 SplitBean
class 的一大优势是,如果您决定需要,您将拥有更大的灵活性执行更多数据转换 - 例如,过滤掉数据行,或以不同方式对数据进行排序。