前言
csv格式的表格,和xls以及xlsx格式的表格有一些不同,不能够直接用处理xls的方式处理csv;
以下我将介绍如何读取并写入csv数据
准备工作
要处理csv格式的表格数据,我们首先需要引入pom.xml的依赖
<dependency>
<artifactId>commons-csv</artifactId>
<groupId>org.apache.commons</groupId>
<version>1.8</version>
</dependency>
<dependency>
读取
前端
一般情况下,我们都是使用前后端交互获取到csv文件,那么前端应该是写一个file类型的input接收文件,为演示方便使用原生的组件
// 上传文件的组件
<input type="file" id="fileInput" name="file">
// 点击上传文件
<button type="button" onclick="uploadFile()">上传</button>
其中js逻辑如下:
// 上传文件方法
function uploadFile() {
var fileInput = document.getElementById("fileInput");
var file = fileInput.files[0];
var formData = new FormData();
formData.append("file", file);
// 此处调用后端接口上传文件
}
ps:需要注意的是,为了正确上传成功文件,我们的请求应该为:multipart/form-data
如果你使用ajax上传,示例如下:
export function uploadFileInterface(obj) {
return service.post('/xxx', obj, {
headers: { 'Content-Type': 'multipart/form-data' }
})
其中service为我封装的ajax的js
代码如下:
import axios from 'axios'
// 创建axios实例
// eslint-disable-next-line no-unused-vars
const service = axios.create({
baseURL: '/', // api的base_Url
timeout: 50000 // 请求超时时间
});
// 请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error)
}
)
// 响应拦截器
axios.interceptors.response.use(
function (config) {
// 对响应数据做点什么
return config
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error)
}
)
export default service
后端
我的csv文件如下图所示:
读取到的数据为:
后端接收文件的逻辑如下:
@POST
@Path("/getFile")
public String submitOriginalFile(FormDataMultiPart form) {
// 拿取前端标识的文件
// 获取文件流
InputStream fileIns = form.getField("file").getValueAs(InputStream.class);
// 获取文件名,中文不乱码写法
String name = new String(form.getField("file").getContentDisposition()
.getFileName().getBytes("iso-8859-1"), "UTF-8");
// 将文件流转byte,可作为其他情况存储起来处理
byte[] fileBytes = new InputStreamToByteArray(fileIns);
// 将byte数组转csv数据
List<CSVRecord> csvData = new FormDataMultiPartJob().byteToCsvFileData(fileBytes);
// 遍历每一行的数据
for (int i = 0; i < csvData.size(); i++) {
System.out.println("每一行数据:" + csvData.get(i));
for(int j = 0; j < csvData.get(i).size(); j++) {
System.out.println("每一行下每一个单元格数据:" + csvData.get(i).get(j));
}
}
return "读取成功!";
}
文件流转byte数组
/**
* 文件流转byte
*/
public byte[] InputStreamToByteArray(InputStream inputStream) {
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer;
int len;
byte[] buf = new byte[2048];
while ((len = bufferedInputStream.read(buf)) != -1) {
byteArrayOutputStream.write(buf, 0, len);
}
byteArrayOutputStream.flush();
buffer = byteArrayOutputStream.toByteArray();
inputStream.close();
bufferedInputStream.close();
byteArrayOutputStream.close();
return buffer;
} catch (Exception e) {
return null;
}
}
byte数组转csv数据
/**
* byte转csv数据
*/
public List<CSVRecord> byteToCsvFileData(byte[] bytes) {
List<CSVRecord> records = new ArrayList<>();
try {
// 将 byte 数组转为 InputStreamReader 对象
InputStreamReader in = new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8");
// 创建csvParser对象
CSVFormat csvFormat = CSVFormat.EXCEL;
CSVParser parser = new CSVParser(in, csvFormat);
// 读取CSV数据行
records = parser.getRecords();
parser.close();
in.close();
} catch (Exception e) {
return null;
}
return records;
}
写入
如果需要新建csv文件并往里面写数据,参考如下代码:
try (CSVPrinter printer = new CSVPrinter(new FileWriter("data.csv"), CSVFormat.DEFAULT)) {
List<String> header = Arrays.asList("Name", "Age", "Email");
printer.printRecord(header);
List<List<String>> data = Arrays.asList(
Arrays.asList("John", "25", "john@example.com"),
Arrays.asList("Alice", "30", "alice@example.com"),
Arrays.asList("Bob", "40", "bob@example.com")
);
for (List<String> rowData : data) {
printer.printRecord(rowData);
}
} catch (IOException e) {
e.printStackTrace();
}
上面的代码中,我们创建了一个名为 data.csv 的新 CSV 文件,并打开了一个 CSVPrinter 对象。printRecord方法用于打印数据行。
首先,我们打印了一个标题行。标题行包含列的名称。我们将标题行表示为 List 对象 header,并将其传递给 printRecord 方法以打印到文件中
其次,我们打印了一些数据行。数据行包含实际的数据。我们将所有数据行表示为、嵌套的 List 对象 data,并使用 for 循环将每行数据打印到文件中。
需要注意的是,这里使用到了 try-with-resources 语句块来确保 CSVPrinter 能够正确关闭。如果在使用 CSVPrinter 时发生任何异常,它都会在 try-with-resources 语句块结束时被捕获并关闭。
如果你需要使用不同的分隔符或者引号字符来定制 CSV 文件格式,你可以在创建 CSVPrinter 时指定对应的 CSVFormat 对象。例如,如果你要使用制表符作为分隔符,你可以使用以下代码创建 CSVPrinter:
CSVFormat format = CSVFormat.TDF.withHeader("Name", "Age", "Email");
try (CSVPrinter printer = new CSVPrinter(new FileWriter("data.tsv"), format)) {
// 逻辑同上
} catch (IOException e) {
e.printStackTrace();
}
以上代码会写成一个csv文件保存在你的工程文件里,假如你不想生成文件,而只想拿到byte数组数据做其他操作,参考如下:
try (ByteArrayOutputStream stream = new ByteArrayOutputStream();
CSVPrinter printer = new CSVPrinter(new OutputStreamWriter(stream), CSVFormat.DEFAULT)) {
List<String> header = Arrays.asList("Name", "Age", "Email");
printer.printRecord(header);
List<List<String>> data = Arrays.asList(
Arrays.asList("John", "25", "john@example.com"),
Arrays.asList("Alice", "30", "alice@example.com"),
Arrays.asList("Bob", "40", "bob@example.com")
);
for (List<String> rowData : data) {
printer.printRecord(rowData);
}
// byte数组
byte[] bytes = stream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
结语
以上就是如何获取并写入csv文件的过程