File handling & data persistence (CSV/JSON)

บทนำ: ทำไมต้อง Save ข้อมูล?

เมื่อโปรแกรมทำงานเสร็จ ข้อมูลทั้งหมด (ในตัวแปร, ArrayList, HashMap) จะ หายไป ถ้าปิดโปรแกรม

Data Persistence = บันทึกข้อมูลลงไฟล์ เพื่อให้:

  • ข้อมูลไม่หายเมื่อปิดโปรแกรม
  • ข้อมูลสามารถใช้ได้ครั้งหน้า
  • แชร์ข้อมูลระหว่างโปรแกรมต่างๆ

รูปแบบยอดนิยม:

  • CSV (Comma-Separated Values) – ง่าย, flat data
  • JSON (JavaScript Object Notation) – structured, ยืดหยุ่น

CSV: บันทึกข้อมูลแบบตารางอย่างง่าย

ตัวอย่างที่ 1: เขียน CSV File

javaimport java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Student {
    private int id;
    private String name;
    private double score;
    
    public Student(int id, String name, double score) {
        this.id = id;
        this.name = name;
        this.score = score;
    }
    
    public int getId() { return id; }
    public String getName() { return name; }
    public double getScore() { return score; }
}

public class CSVWriter {
    // เขียน students ลง CSV file
    public static void writeStudentsToCSV(List<Student> students, String filename) {
        try (FileWriter writer = new FileWriter(filename)) {
            // เขียน header
            writer.write("ID,Name,Score\n");
            
            // เขียนข้อมูล
            for (Student student : students) {
                writer.write(student.getId() + "," + 
                            student.getName() + "," + 
                            student.getScore() + "\n");
            }
            
            System.out.println("✓ บันทึก CSV สำเร็จ: " + filename);
        } catch (IOException e) {
            System.out.println("❌ ข้อผิดพลาด: " + e.getMessage());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // สร้าง list ของ students
        List<Student> students = new ArrayList<>();
        students.add(new Student(1, "สมชาย", 85));
        students.add(new Student(2, "สมหญิง", 90));
        students.add(new Student(3, "สมศรี", 78));
        students.add(new Student(4, "ชัยวัฒน์", 88));
        
        // เขียนลง CSV file
        CSVWriter.writeStudentsToCSV(students, "students.csv");
    }
}

Output (students.csv):

textID,Name,Score
1,สมชาย,85.0
2,สมหญิง,90.0
3,สมศรี,78.0
4,ชัยวัฒน์,88.0

คำอธิบาย:

  • FileWriter = เขียนข้อมูล string ลงไฟล์
  • try-with-resources = auto-close file
  • แต่ละบรรทัด = หนึ่ง record
  • column คั่นด้วย , (comma)

ตัวอย่างที่ 2: อ่าน CSV File

javaimport java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CSVReader {
    // อ่าน CSV file และ return list ของ students
    public static List<Student> readStudentsFromCSV(String filename) {
        List<Student> students = new ArrayList<>();
        
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            boolean firstLine = true;  // Skip header
            
            while ((line = reader.readLine()) != null) {
                if (firstLine) {
                    firstLine = false;
                    continue;  // ข้าม header
                }
                
                // Split ด้วย comma
                String[] parts = line.split(",");
                
                if (parts.length == 3) {
                    int id = Integer.parseInt(parts[0].trim());
                    String name = parts[1].trim();
                    double score = Double.parseDouble(parts[2].trim());
                    
                    students.add(new Student(id, name, score));
                }
            }
            
            System.out.println("✓ อ่าน CSV สำเร็จ: " + filename);
        } catch (IOException e) {
            System.out.println("❌ ข้อผิดพลาด: " + e.getMessage());
        }
        
        return students;
    }
}

public class Main {
    public static void main(String[] args) {
        // อ่าน CSV file
        List<Student> students = CSVReader.readStudentsFromCSV("students.csv");
        
        // แสดงข้อมูล
        System.out.println("\n=== ข้อมูล Students ===");
        for (Student student : students) {
            System.out.println("ID: " + student.getId() + 
                             ", ชื่อ: " + student.getName() + 
                             ", คะแนน: " + student.getScore());
        }
        
        // คำนวณค่าเฉลี่ย
        double average = students.stream()
                                 .mapToDouble(Student::getScore)
                                 .average()
                                 .orElse(0);
        System.out.println("\nคะแนนเฉลี่ย: " + average);
    }
}

Output:

text✓ อ่าน CSV สำเร็จ: students.csv

=== ข้อมูล Students ===
ID: 1, ชื่อ: สมชาย, คะแนน: 85.0
ID: 2, ชื่อ: สมหญิง, คะแนน: 90.0
ID: 3, ชื่อ: สมศรี, คะแนน: 78.0
ID: 4, ชื่อ: ชัยวัฒน์, คะแนน: 88.0

คะแนนเฉลี่ย: 85.25

คำอธิบาย:

  • BufferedReader = อ่าน file ทีละบรรทัด (efficient)
  • .split(",") = แยก string ด้วย comma
  • .trim() = ลบ whitespace ด้านหน้า-ด้านหลัง
  • ข้ามบรรทัดแรก (header)

JSON: บันทึกข้อมูลแบบ Structured

บทนำ JSON

JSON = ตัวอักษรและสัญลักษณ์ที่อ่านได้ง่าย สำหรับเก็บข้อมูล

json{
  "id": 1,
  "name": "สมชาย",
  "score": 85,
  "subjects": ["Math", "English", "Science"]
}

ตัวอย่างที่ 3: เขียน JSON File (ใช้ Library)

Java ไม่มี built-in JSON library ที่สมบูรณ์ แต่เราสามารถใช้ org.json library

javaimport org.json.JSONArray;
import org.json.JSONObject;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class JSONWriter {
    public static void writeStudentsToJSON(List<Student> students, String filename) {
        try (FileWriter writer = new FileWriter(filename)) {
            JSONArray jsonArray = new JSONArray();
            
            for (Student student : students) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("id", student.getId());
                jsonObject.put("name", student.getName());
                jsonObject.put("score", student.getScore());
                
                jsonArray.put(jsonObject);
            }
            
            // เขียนลงไฟล์
            writer.write(jsonArray.toString(2));  // 2 = indent
            
            System.out.println("✓ บันทึก JSON สำเร็จ: " + filename);
        } catch (IOException e) {
            System.out.println("❌ ข้อผิดพลาด: " + e.getMessage());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(1, "สมชาย", 85));
        students.add(new Student(2, "สมหญิง", 90));
        
        JSONWriter.writeStudentsToJSON(students, "students.json");
    }
}

Output (students.json):

json[
  {
    "id": 1,
    "name": "สมชาย",
    "score": 85
  },
  {
    "id": 2,
    "name": "สมหญิง",
    "score": 90
  }
]

ตัวอย่างที่ 4: อ่าน JSON File

javaimport org.json.JSONArray;
import org.json.JSONObject;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class JSONReader {
    public static List<Student> readStudentsFromJSON(String filename) {
        List<Student> students = new ArrayList<>();
        
        try {
            // อ่าน file เป็น string
            String content = new String(Files.readAllBytes(Paths.get(filename)));
            
            // Parse JSON
            JSONArray jsonArray = new JSONArray(content);
            
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                
                int id = jsonObject.getInt("id");
                String name = jsonObject.getString("name");
                double score = jsonObject.getDouble("score");
                
                students.add(new Student(id, name, score));
            }
            
            System.out.println("✓ อ่าน JSON สำเร็จ: " + filename);
        } catch (Exception e) {
            System.out.println("❌ ข้อผิดพลาด: " + e.getMessage());
        }
        
        return students;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Student> students = JSONReader.readStudentsFromJSON("students.json");
        
        System.out.println("\n=== ข้อมูล Students ===");
        for (Student student : students) {
            System.out.println("ID: " + student.getId() + 
                             ", ชื่อ: " + student.getName() + 
                             ", คะแนน: " + student.getScore());
        }
    }
}

Output:

text✓ อ่าน JSON สำเร็จ: students.json

=== ข้อมูล Students ===
ID: 1, ชื่อ: สมชาย, คะแนน: 85.0
ID: 2, ชื่อ: สมหญิง, คะแนน: 90.0

ตัวอย่างที่ 5: Compare CSV vs JSON

javaimport java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(1, "สมชาย", 85));
        students.add(new Student(2, "สมหญิง", 90));
        
        System.out.println("=== Write Both CSV and JSON ===");
        
        // เขียน CSV
        CSVWriter.writeStudentsToCSV(students, "students.csv");
        
        // เขียน JSON
        JSONWriter.writeStudentsToJSON(students, "students.json");
        
        System.out.println("\n=== Read Both Formats ===");
        
        // อ่าน CSV
        List<Student> fromCSV = CSVReader.readStudentsFromCSV("students.csv");
        System.out.println("CSV Students: " + fromCSV.size());
        
        // อ่าน JSON
        List<Student> fromJSON = JSONReader.readStudentsFromJSON("students.json");
        System.out.println("JSON Students: " + fromJSON.size());
    }
}

Output:

text=== Write Both CSV and JSON ===
✓ บันทึก CSV สำเร็จ: students.csv
✓ บันทึก JSON สำเร็จ: students.json

=== Read Both Formats ===
✓ อ่าน CSV สำเร็จ: students.csv
CSV Students: 2
✓ อ่าน JSON สำเร็จ: students.json
JSON Students: 2

ตัวอย่างที่ 6: File Operations – Delete, Check Existence

javaimport java.io.File;

public class FileOperations {
    public static void main(String[] args) {
        String filename = "students.csv";
        File file = new File(filename);
        
        // ==== ตรวจสอบว่ามีไฟล์ ====
        if (file.exists()) {
            System.out.println("✓ ไฟล์มีอยู่: " + filename);
        } else {
            System.out.println("❌ ไฟล์ไม่มีอยู่: " + filename);
        }
        
        // ==== ข้อมูลไฟล์ ====
        if (file.exists()) {
            System.out.println("ชื่อ: " + file.getName());
            System.out.println("เส้นทาง: " + file.getAbsolutePath());
            System.out.println("ขนาด: " + file.length() + " bytes");
            System.out.println("แก้ไขครั้งสุดท้าย: " + file.lastModified());
        }
        
        // ==== ลบไฟล์ ====
        // if (file.delete()) {
        //     System.out.println("✓ ลบไฟล์สำเร็จ");
        // } else {
        //     System.out.println("❌ ลบไฟล์ไม่สำเร็จ");
        // }
        
        // ==== สร้างโฟลเดอร์ ====
        File dir = new File("data");
        if (!dir.exists()) {
            dir.mkdir();
            System.out.println("✓ สร้างโฟลเดอร์: " + dir.getName());
        }
    }
}

Output:

text✓ ไฟล์มีอยู่: students.csv
ชื่อ: students.csv
เส้นทาง: /path/to/students.csv
ขนาด: 65 bytes
แก้ไขครั้งสุดท้าย: 1699255678900
✓ สร้างโฟลเดอร์: data

ตัวอย่างรวม: Simple Database Application

javaimport java.io.*;
import java.util.*;

// ==== Product Class ====
public class Product {
    private int id;
    private String name;
    private double price;
    private int quantity;
    
    public Product(int id, String name, double price, int quantity) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }
    
    public int getId() { return id; }
    public String getName() { return name; }
    public double getPrice() { return price; }
    public int getQuantity() { return quantity; }
}

// ==== Database Manager ====
public class ProductDatabase {
    private String filename;
    private List<Product> products = new ArrayList<>();
    
    public ProductDatabase(String filename) {
        this.filename = filename;
        loadFromFile();
    }
    
    public void addProduct(Product product) {
        products.add(product);
        saveToFile();
        System.out.println("✓ เพิ่มสินค้า: " + product.getName());
    }
    
    public void displayAll() {
        System.out.println("\n=== สินค้าทั้งหมด ===");
        if (products.isEmpty()) {
            System.out.println("ไม่มีสินค้า");
            return;
        }
        
        for (Product p : products) {
            System.out.printf("ID:%d | %s | %.2f บาท | %d ชิ้น\n",
                p.getId(), p.getName(), p.getPrice(), p.getQuantity());
        }
    }
    
    // ==== Save ลง CSV ====
    private void saveToFile() {
        try (FileWriter writer = new FileWriter(filename)) {
            writer.write("ID,Name,Price,Quantity\n");
            
            for (Product p : products) {
                writer.write(p.getId() + "," + 
                            p.getName() + "," + 
                            p.getPrice() + "," + 
                            p.getQuantity() + "\n");
            }
        } catch (IOException e) {
            System.out.println("❌ ข้อผิดพลาด save: " + e.getMessage());
        }
    }
    
    // ==== Load จาก CSV ====
    private void loadFromFile() {
        File file = new File(filename);
        if (!file.exists()) {
            System.out.println("ไฟล์ใหม่: " + filename);
            return;
        }
        
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            boolean firstLine = true;
            
            while ((line = reader.readLine()) != null) {
                if (firstLine) {
                    firstLine = false;
                    continue;
                }
                
                String[] parts = line.split(",");
                if (parts.length == 4) {
                    int id = Integer.parseInt(parts[0].trim());
                    String name = parts[1].trim();
                    double price = Double.parseDouble(parts[2].trim());
                    int qty = Integer.parseInt(parts[3].trim());
                    
                    products.add(new Product(id, name, price, qty));
                }
            }
            
            System.out.println("✓ โหลดสินค้า: " + products.size() + " รายการ");
        } catch (IOException e) {
            System.out.println("❌ ข้อผิดพลาด load: " + e.getMessage());
        }
    }
}

// ==== Main ====
public class Main {
    public static void main(String[] args) {
        ProductDatabase db = new ProductDatabase("products.csv");
        
        // เพิ่มสินค้า
        db.addProduct(new Product(1, "Notebook", 50, 100));
        db.addProduct(new Product(2, "Pen", 10, 500));
        db.addProduct(new Product(3, "Pencil", 5, 1000));
        
        // แสดงข้อมูล
        db.displayAll();
        
        System.out.println("\n(ข้อมูลถูกบันทึกลงไฟล์ products.csv)");
        System.out.println("ครั้งต่อไปที่รัน จะโหลดข้อมูลเดิมมาให้");
    }
}

Output (ครั้งแรก):

textไฟล์ใหม่: products.csv
✓ เพิ่มสินค้า: Notebook
✓ เพิ่มสินค้า: Pen
✓ เพิ่มสินค้า: Pencil

=== สินค้าทั้งหมด ===
ID:1 | Notebook | 50.00 บาท | 100 ชิ้น
ID:2 | Pen | 10.00 บาท | 500 ชิ้น
ID:3 | Pencil | 5.00 บาท | 1000 ชิ้น

(ข้อมูลถูกบันทึกลงไฟล์ products.csv)
ครั้งต่อไปที่รัน จะโหลดข้อมูลเดิมมาให้

Output (ครั้งที่ 2 – โหลดข้อมูลเก่า):

text✓ โหลดสินค้า: 3 รายการ

=== สินค้าทั้งหมด ===
ID:1 | Notebook | 50.00 บาท | 100 ชิ้น
ID:2 | Pen | 10.00 บาท | 500 ชิ้น
ID:3 | Pencil | 5.00 บาท | 1000 ชิ้น

(ข้อมูลถูกบันทึกลงไฟล์ products.csv)
ครั้งต่อไปที่รัน จะโหลดข้อมูลเดิมมาให้

ตารางเปรียบเทียบ CSV vs JSON

เกณฑ์CSVJSON
ง่ายใช้✓ ง่ายมาก✓ ค่อนข้างง่าย
ความสามารถข้อมูลแบบตารางข้อมูลแบบ nested/complex
ขนาดไฟล์เล็กใหญ่กว่า (เพราะ tags)
ความเข้าใจตรงไปตรงมามีโครงสร้าง
ความเรียบง่ายกำลังดียืดหยุ่นกว่า
ใช้เมื่อไรสเปรดชีต, สถิติAPIs, config files

Best Practices: File Handling

ทำได้ไม่ทำ
✓ ใช้ try-with-resources❌ ลืม close file
✓ ตรวจสอบ file exists❌ Assume file มีอยู่
✓ Handle IOException❌ Ignore exception
✓ ทำให้เส้นทาง configurable❌ Hardcode path
✓ Backup ข้อมูลเก่า❌ Overwrite โดยไม่ระวัง
✓ Validate data❌ Save ข้อมูลผิด

สรุป

File Handling & Data Persistence ทำให้โปรแกรมของเรา:

  • ยาวนาน – ข้อมูลไม่หายเมื่อปิด
  • เชื่อถือได้ – สามารถกู้คืนข้อมูลได้
  • แชร์ได้ – แลกเปลี่ยนข้อมูลระหว่างโปรแกรม

CSV เหมาะสำหรับ:

  • ข้อมูลแบบตาราง (แถว-คอลัมน์)
  • ไฟล์ที่ export ไปยัง Excel
  • ข้อมูลที่ไม่มี nested structure

JSON เหมาะสำหรับ:

  • ข้อมูลที่มีโครงสร้างซับซ้อน
  • APIs และ config files
  • ข้อมูลที่ต้อง nested/hierachical

การจัดการไฟล์อย่างถูกต้อง ด้วย exception handling และการปิด resources อย่างแน่นอน จะทำให้โปรแกรมของเรา:

  • ปลอดภัย – ไม่รั่ว resource
  • เสถียร – ไม่ crash เมื่อเกิดข้อผิดพลาด
  • เป็นมืออาชีพ – ดูแลรักษาข้อมูลอย่างเหมาะสม

เมื่อรวม Collections, Exception Handling, และ File I/O เข้าด้วยกัน คุณจะมีความสามารถในการสร้าง application ที่สมบูรณ์ – รับข้อมูล, ประมวลผล, บันทึก, และโหลดให้ใช้ได้