首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 將固定寬度文字檔轉換為 CSV 輸出:固定欄位解析類別實作

     編輯:PHP 相關知識

應用場景

舊系統常以固定寬度文字檔交換資料(如銀行匯入檔、主機下載報表)。需將其轉為 CSV 才能匯入資料庫或試算表處理。

核心類別:fixed2CSV

繼承 SplFileObject,利用迭代器逐行處理,記憶體效率高。支援自訂欄位位置/寬度、分隔符、換行符。

<?php
/**
 * 固定寬度文字檔轉 CSV 類別
 * 
 * @author Kevin Waterson (改寫優化)
 */
class Fixed2CSV extends SplFileObject {
    private $fields = [];      // [起始位置 => 寬度]
    private $separator = ',';
    private $eol = "\n";

    public function __construct(string $filename) {
        parent::__construct($filename);
    }

    // 魔術方法:設定屬性
    public function __set(string $name, $value): void {
        switch ($name) {
            case 'fields':
                if (!is_array($value)) throw new InvalidArgumentException('fields 必須為陣列');
                $this->fields = $value;
                break;
            case 'separator':
                $this->separator = (string)$value;
                break;
            case 'eol':
                $this->eol = (string)$value;
                break;
            default:
                throw new Exception("無法設定屬性: $name");
        }
    }

    // 魔術方法:取得屬性預設值
    public function __get(string $name) {
        switch ($name) {
            case 'fields': return [];
            case 'separator': return ',';
            case 'eol': return "\n";
            default: throw new Exception("屬性不存在: $name");
        }
    }

    // 覆寫 current():將固定寬度行轉為 CSV
    public function current(): string|false {
        $line = parent::current();
        if ($line === false) return false;

        $csv = '';
        $fieldKeys = array_keys($this->fields);
        $fieldCount = count($fieldKeys);

        foreach ($fieldKeys as $i => $start) {
            $width = $this->fields[$start];
            $fieldValue = trim(substr($line, $start, $width));
            $csv .= $fieldValue;
            $csv .= ($i < $fieldCount - 1) ? $this->separator : $this->eol;
        }
        return $csv;
    }
}

使用範例

<?php
require_once 'Fixed2CSV.php';

try {
    // 範例:每行 80 字元,欄位定義
    // 欄位1:位置 0,寬度 10
    // 欄位2:位置 10,寬度 15
    // 欄位3:位置 25,寬度 20
    // 欄位4:位置 45,寬度 25
    $file = new Fixed2CSV('data/fixed_width.txt');
    $file->fields = [
        0  => 10,
        10 => 15,
        25 => 20,
        45 => 25,
    ];
    $file->separator = ',';
    $file->eol = "\n";

    echo "完整欄位輸出:\n";
    foreach ($file as $line) {
        echo $line;
    }

    // 僅輸出第 1、3 欄位
    $file2 = new Fixed2CSV('data/fixed_width.txt');
    $file2->fields = [
        0  => 10,
        25 => 20,
    ];
    echo "\n僅第 1、3 欄位:\n";
    foreach ($file2 as $line) {
        echo $line;
    }

} catch (Exception $e) {
    echo "錯誤: " . $e->getMessage();
}

輸入檔案範例 (fixed_width.txt)

ID001     NAME001          TAIPEI       20240101
ID002     NAME002          TAICHUNG     20240102
ID003     NAME003          KAOHSIUNG    20240103

輸出結果

ID001,NAME001,TAIPEI,20240101
ID002,NAME002,TAICHUNG,20240102
ID003,NAME003,KAOHSIUNG,20240103

進階應用

  • 直接寫入資料庫:搭配 LOAD DATA INFILE 或 PDO 批次匯入
  • 處理編碼:建構子加入 $this->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY),或使用 iconv() 轉 UTF-8
  • 欄位型別轉換:在 current() 中依欄位索引做 intval()、floatval()、日期解析
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved