Skip to content

Commit 6a6f3ad

Browse files
committed
feat(csv): 增加CSV操作
1 parent 935bcd7 commit 6a6f3ad

3 files changed

Lines changed: 114 additions & 2 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ So, I’ve compiled these simple and frequently-used methods into this toolkit.
8080
| FileUtils::getCommonLinesFromFiles() | Get intersecting lines from multiple files |
8181
| FileUtils::extractColumnFromCsvFiles() | Quickly extract columns from multiple CSV files |
8282

83+
### CSV operation
84+
85+
| Method | Explanation |
86+
| :-------------------- | :--------------------------------- |
87+
| Csv::readCsvToArray() | Read CSV file and convert to array |
88+
| Csv::arrayToCsv() | Write the array to a CSV file |
89+
8390
### Network Request Operations
8491

8592
| method | describe |

README.zh-CN.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,20 @@ composer require hejunjie/utils
8181
| FileUtils::getCommonLinesFromFiles() | 从多个文件中获取交集行 |
8282
| FileUtils::extractColumnFromCsvFiles() | 从多个 csv 文件中快速提取列 |
8383

84+
### CSV 操作
85+
86+
| 方法 | 说明 |
87+
| :-------------------- | :------------------------ |
88+
| Csv::readCsvToArray() | 读取 CSV 文件并转换为数组 |
89+
| Csv::arrayToCsv() | 将数组写入 CSV 文件 |
90+
8491
### 网络请求操作
8592

8693
| 方法 | 说明 |
8794
| :---------------------------- | :----------------------- |
8895
| HttpClient::sendGetRequest() | 使用 cURL 发送 GET 请求 |
8996
| HttpClient::sendPostRequest() | 使用 cURL 发送 POST 请求 |
90-
| HttpClient::downloadFile() | 下载远程文件并保存到本地 |
97+
| HttpClient::downloadFile() | 下载远程文件并保存到本地 |
9198

9299
### 图片操作
93100

@@ -133,7 +140,7 @@ composer require hejunjie/tools
133140

134141
[hejunjie/address-parser](https://github.com/zxc7563598/php-address-parser) - 收货地址智能解析工具,支持从非结构化文本中提取姓名、手机号、身份证号、省市区、详细地址等字段,适用于电商、物流、CRM 等系统。
135142

136-
[hejunjie/url-signer](https://github.com/zxc7563598/php-url-signer) - 用于生成带签名和加密保护的URL链接的PHP工具包,适用于需要保护资源访问的场景
143+
[hejunjie/url-signer](https://github.com/zxc7563598/php-url-signer) - 用于生成带签名和加密保护的 URL 链接的 PHP 工具包,适用于需要保护资源访问的场景
137144

138145
[hejunjie/google-authenticator](https://github.com/zxc7563598/php-google-authenticator) - 一个用于生成和验证时间基础一次性密码(TOTP)的 PHP 包,支持 Google Authenticator 及类似应用。功能包括密钥生成、二维码创建和 OTP 验证。
139146

src/Csv.php

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
namespace Hejunjie\Csv;
4+
5+
use Exception;
6+
7+
/**
8+
* CSV处理类
9+
*
10+
* @package Hejunjie\Csv
11+
*/
12+
class Csv
13+
{
14+
15+
/**
16+
* 读取 CSV 文件并转换为数组
17+
*
18+
* @param string $csvPath CSV 文件路径
19+
* @param bool $useHeaderAsKey 是否使用第一行作为 key
20+
* @param string $delimiter CSV 分隔符,默认逗号
21+
*
22+
* @return array
23+
* @throws Exception
24+
*/
25+
function readCsvToArray(string $csvPath, bool $useHeaderAsKey = true, string $delimiter = ','): array
26+
{
27+
if (!is_readable($csvPath)) {
28+
throw new \Exception("CSV 文件不可读: {$csvPath}");
29+
}
30+
$handle = fopen($csvPath, 'r');
31+
if ($handle === false) {
32+
throw new \Exception("无法打开 CSV 文件: {$csvPath}");
33+
}
34+
$result = [];
35+
$header = [];
36+
while (($row = fgetcsv($handle, 0, $delimiter)) !== false) {
37+
if ($useHeaderAsKey && empty($header)) {
38+
$header = $row;
39+
continue;
40+
}
41+
if ($useHeaderAsKey) {
42+
$item = [];
43+
foreach ($header as $index => $key) {
44+
$item[$key] = $row[$index] ?? null;
45+
}
46+
$result[] = $item;
47+
} else {
48+
$result[] = $row;
49+
}
50+
}
51+
fclose($handle);
52+
return $result;
53+
}
54+
55+
/**
56+
* 将数组写入 CSV 文件
57+
*
58+
* @param array $data 要写入的数据
59+
* @param string $filePath CSV 文件保存路径
60+
* @param bool $writeHeader 是否写入表头(仅在二维关联数组时有效)
61+
* @param string $delimiter CSV 分隔符,默认逗号
62+
*
63+
* @return void
64+
* @throws Exception
65+
*/
66+
function arrayToCsv(array $data, string $filePath, bool $writeHeader = true, string $delimiter = ','): void
67+
{
68+
if (empty($data)) {
69+
throw new \Exception('写入 CSV 的数据为空');
70+
}
71+
// 确保目录存在
72+
$dir = dirname($filePath);
73+
if (!is_dir($dir)) {
74+
if (!mkdir($dir, 0777, true) && !is_dir($dir)) {
75+
throw new \Exception("无法创建目录: {$dir}");
76+
}
77+
}
78+
$handle = fopen($filePath, 'w');
79+
if ($handle === false) {
80+
throw new \Exception("无法写入 CSV 文件: {$filePath}");
81+
}
82+
fwrite($handle, "\xEF\xBB\xBF");
83+
$firstRow = reset($data);
84+
$isAssoc = array_keys($firstRow) !== range(0, count($firstRow) - 1);
85+
if ($writeHeader && $isAssoc) {
86+
fputcsv($handle, array_keys($firstRow), $delimiter);
87+
}
88+
// 写数据行
89+
foreach ($data as $row) {
90+
if ($isAssoc) {
91+
fputcsv($handle, array_values($row), $delimiter);
92+
} else {
93+
fputcsv($handle, $row, $delimiter);
94+
}
95+
}
96+
fclose($handle);
97+
}
98+
}

0 commit comments

Comments
 (0)