Takip et

OpenCSV CSVReader CSVWriter Örnekleri ile Kapsamlı CSV İşleme Rehberi

OpenCSV CSVReader CSVWriter Örnekleri ile Kapsamlı CSV İşleme Rehberi Giriş: CSV Dosyaları ve Veri Yönetimindeki Rolü Veri, modern yazılım

OpenCSV CSVReader CSVWriter Örnekleri ile Kapsamlı CSV İşleme Rehberi

Giriş: CSV Dosyaları ve Veri Yönetimindeki Rolü

Veri, modern yazılım uygulamalarının ve iş süreçlerinin temelini oluşturur. Farklı sistemler arasında veri alışverişi yaparken veya büyük veri kümelerini depolarken, verinin standart ve okunabilir bir formatta olması büyük önem taşır. Bu bağlamda, “Comma Separated Values” (CSV) dosyaları, basitliği, evrenselliği ve insan tarafından okunabilirliği sayesinde en yaygın kullanılan veri formatlarından biri haline gelmiştir.

CSV dosyaları, düz metin dosyalarıdır ve her satır bir veri kaydını temsil ederken, her kayıttaki alanlar belirli bir ayırıcı (genellikle virgül, noktalı virgül veya tab) ile ayrılır. Örneğin, bir müşteri listesi, her satırda bir müşteri bilgisi (Ad, Soyad, E-posta, Telefon) ve bu bilgilerin virgülle ayrılması şeklinde bir CSV dosyasında saklanabilir. Bu basit yapı, CSV’yi elektronik tablolar, veritabanları ve çeşitli yazılım uygulamaları arasında veri aktarımı için ideal bir seçim yapar.

Ancak, CSV dosyaları basit görünse de, onları programatik olarak doğru bir şekilde ayrıştırmak (parsing) veya oluşturmak beklenenden daha karmaşık olabilir. Özel karakterler (tırnak işaretleri, ayırıcı karakterler), farklı karakter kodlamaları (UTF-8, ISO-8859-1), boşluklar ve boş alanlar gibi detaylar, manuel olarak yazılan bir ayrıştırıcının hatalara yol açmasına neden olabilir. İşte bu noktada OpenCSV gibi güçlü ve esnek kütüphaneler devreye girer.

OpenCSV Kütüphanesine Genel Bakış

OpenCSV, Java ortamında CSV dosyalarını okuma ve yazma işlemlerini kolaylaştıran açık kaynaklı bir kütüphanedir. CSV spesifikasyonunun çeşitli nüanslarını (örneğin, tırnak işaretleri içindeki virgüller, kaçış karakterleri) ele alarak geliştiricilerin bu karmaşık detaylarla uğraşmak yerine doğrudan veri işleme mantığına odaklanmasını sağlar.

OpenCSV’nin başlıca avantajları şunlardır:

* Basit API: Sezgisel ve kullanımı kolay bir API sunar.
* Esneklik: Özel ayırıcılar, tırnak karakterleri, kaçış karakterleri gibi birçok konfigürasyon seçeneği sunar.
* Güvenilirlik: CSV spesifikasyonunun birçok kenar durumunu (edge case) doğru bir şekilde ele alır.
* Nesne Haritalama: CSV verilerini doğrudan Java nesnelerine dönüştürme ve Java nesnelerinden CSV’ye yazma yeteneği sayesinde geliştirme sürecini hızlandırır ve kodun okunabilirliğini artırır.
* Aktif Geliştirme: Sürekli olarak güncellenen ve topluluk tarafından desteklenen bir kütüphanedir.

Manuel olarak bir CSV ayrıştırıcısı yazmak, özellikle tırnak işaretleri içinde virgül bulunması, yeni satır karakterleri veya özel kaçış dizileri gibi durumlar söz konusu olduğunda oldukça hataya açık ve zaman alıcı bir süreçtir. OpenCSV, bu karmaşıklığı soyutlayarak geliştiricilere sağlam ve test edilmiş bir çözüm sunar.

Kurulum: Maven ve Gradle

OpenCSV’yi projenize dahil etmek oldukça basittir. Projenizin bağımlılık yönetimi aracına (Maven veya Gradle) ilgili bağımlılığı eklemeniz yeterlidir.

Maven Kullanıyorsanız (pom.xml):


    com.opencsv
    opencsv
    5.9 

Gradle Kullanıyorsanız (build.gradle):

implementation 'com.opencsv:opencsv:5.9' // En güncel sürümü kontrol edin

Bu bağımlılığı ekledikten sonra, OpenCSV sınıflarını projenizde kullanmaya başlayabilirsiniz.

CSVReader ile CSV Dosyalarını Okuma

OpenCSV’nin CSVReader sınıfı, CSV dosyalarından veri okumak için temel bileşendir. Bu sınıf, CSV dosyasını satır satır veya tek seferde okuyabilir, ayrıca çeşitli konfigürasyon seçenekleriyle esnek okuma imkanları sunar.

Temel CSV Okuma İşlemleri

CSVReader, bir Reader nesnesi (örneğin, FileReader) alır ve CSV verilerini ayrıştırmak için kullanılır. En basit kullanım senaryosunda, dosyadaki her satırı bir String dizisi (String[]) olarak okuyabiliriz.

Öncelikle, okuyacağımız bir CSV dosyası oluşturalım. veri.csv adında bir dosya ve içeriği şöyle olsun:

Ad,Soyad,Yaş,Şehir
Ali,Can,30,Ankara
Ayşe,Yılmaz,25,İstanbul
Mehmet,Demir,40,İzmir
"Fatma,Gül",35,Bursa

Yukarıdaki örnekte “Fatma,Gül” ismindeki virgülün tırnak işaretleri içine alındığına dikkat edin. OpenCSV bunu otomatik olarak tek bir alan olarak algılayacaktır.

1. Satır Satır Okuma (Line by Line):

Bu yöntem, özellikle büyük CSV dosyalarını işlerken bellek verimliliği açısından tercih edilir. Her readNext() çağrısı bir sonraki CSV satırını String[] olarak döndürür.

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;

import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

public class CsvReaderTemelOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri.csv";

        try (CSVReader reader = new CSVReader(new FileReader(dosyaYolu))) {
            String[] nextLine;
            int satirSayisi = 0;

            // İlk satırı (başlık) oku ve atla
            reader.readNext(); // Veya isterseniz başlık satırını işleyebilirsiniz.
            satirSayisi++;

            while ((nextLine = reader.readNext()) != null) {
                System.out.println("Satır " + (satirSayisi + 1) + ": " + Arrays.toString(nextLine));
                satirSayisi++;
            }
            System.out.println("Toplam " + (satirSayisi) + " satır okundu.");

        } catch (IOException | CsvValidationException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Çıktı:

Satır 2: [Ali, Can, 30, Ankara]
Satır 3: [Ayşe, Yılmaz, 25, İstanbul]
Satır 4: [Mehmet, Demir, 40, İzmir]
Satır 5: [Fatma,Gül, 35, Bursa]
Toplam 5 satır okundu.

try-with-resources yapısı, CSVReader ve FileReader kaynaklarının otomatik olarak kapatılmasını sağlayarak olası kaynak sızıntılarını önler. CsvValidationException, CSV verilerinde ayrıştırma kurallarına uymayan bir durum olduğunda fırlatılır.

2. Tüm Satırları Bir Kerede Okuma:

Daha küçük CSV dosyaları için tüm veriyi belleğe yüklemek pratik olabilir. readAll() metodu, dosyadaki tüm satırları List olarak döndürür.

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException; // CsvValidationException'ın süper sınıfı

import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;

public class CsvReaderReadAllOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri.csv";

        try (CSVReader reader = new CSVReader(new FileReader(dosyaYolu))) {
            List tumVeri = reader.readAll();

            // İlk satır genellikle başlık olduğu için onu ayrı işleyebiliriz.
            if (!tumVeri.isEmpty()) {
                String[] baslik = tumVeri.get(0);
                System.out.println("Başlık: " + Arrays.toString(baslik));

                for (int i = 1; i < tumVeri.size(); i++) { // Başlıktan sonraki satırları işle
                    System.out.println("Veri Satırı " + i + ": " + Arrays.toString(tumVeri.get(i)));
                }
            }
            System.out.println("Toplam " + tumVeri.size() + " satır okundu.");

        } catch (IOException | CsvException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Çıktı:

Başlık: [Ad, Soyad, Yaş, Şehir]
Veri Satırı 1: [Ali, Can, 30, Ankara]
Veri Satırı 2: [Ayşe, Yılmaz, 25, İstanbul]
Veri Satırı 3: [Mehmet, Demir, 40, İzmir]
Veri Satırı 4: [Fatma,Gül, 35, Bursa]
Toplam 5 satır okundu.

Gelişmiş CSV Okuma Konfigürasyonları

OpenCSV, CSVReaderBuilder sınıfı aracılığıyla CSV okuma işlemini daha da özelleştirmenize olanak tanır. Bu, standart virgül ayırıcılı CSV'lerden farklı formatlara sahip dosyaları işlerken çok kullanışlıdır.

1. Özel Ayırıcı (Delimiter) Kullanımı:

Bazı CSV benzeri dosyalar virgül yerine noktalı virgül, tab veya başka bir karakter kullanabilir. withSeparator() metodu ile bu ayırıcıyı belirleyebilirsiniz.

Örneğin, veri_noktali_virgul.csv dosyası:

Ad;Soyad;Yaş;Şehir
Ali;Can;30;Ankara
Ayşe;Yılmaz;25;İstanbul
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvValidationException;

import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

public class CsvReaderOzelAyiriciOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri_noktali_virgul.csv";

        try (CSVReader reader = new CSVReaderBuilder(new FileReader(dosyaYolu))
                .withSeparator(';') // Noktalı virgül ayırıcı kullan
                .build()) {

            String[] nextLine;
            while ((nextLine = reader.readNext()) != null) {
                System.out.println(Arrays.toString(nextLine));
            }

        } catch (IOException | CsvValidationException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

2. Özel Tırnak (Quote) Karakteri Kullanımı:

Varsayılan olarak, OpenCSV çift tırnak (") karakterini tırnak karakteri olarak kabul eder. Bazı durumlarda tek tırnak (') veya başka bir karakter kullanılabilir. withQuoteChar() metodu ile bu ayarı yapabilirsiniz.

// ... (İlgili importlar)
import com.opencsv.CSVReaderBuilder;

public class CsvReaderOzelTirnakOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri_tek_tirnak.csv"; // Örn: 'Ad','Soyad'
        // veri_tek_tirnak.csv içeriği: 'Ad','Soyad','Yaş' \n 'Ali','Can',30

        try (CSVReader reader = new CSVReaderBuilder(new FileReader(dosyaYolu))
                .withQuoteChar('\'') // Tek tırnak karakteri kullan
                .build()) {

            String[] nextLine;
            while ((nextLine = reader.readNext()) != null) {
                System.out.println(Arrays.toString(nextLine));
            }

        } catch (IOException | CsvValidationException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

3. Başlık Satırını Atlama (Skipping Lines):

Çoğu CSV dosyasının ilk satırı başlık bilgilerini içerir ve bu satırı veri olarak işlemek istemeyebilirsiniz. withSkipLines() metodu ile belirli sayıda satırı atlayabilirsiniz.

// ... (İlgili importlar)
import com.opencsv.CSVReaderBuilder;

public class CsvReaderBaslikAtlaOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri.csv"; // Başlık içeren dosya

        try (CSVReader reader = new CSVReaderBuilder(new FileReader(dosyaYolu))
                .withSkipLines(1) // İlk satırı atla (başlık)
                .build()) {

            String[] nextLine;
            while ((nextLine = reader.readNext()) != null) {
                System.out.println(Arrays.toString(nextLine));
            }

        } catch (IOException | CsvValidationException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Çıktı (Başlık hariç):

[Ali, Can, 30, Ankara]
[Ayşe, Yılmaz, 25, İstanbul]
[Mehmet, Demir, 40, İzmir]
[Fatma,Gül, 35, Bursa]

CSVReaderBuilder, bu ve benzeri birçok konfigürasyon seçeneğini (örneğin, withEscapeChar(), withStrictQuotes()) birleştirerek karmaşık CSV formatlarını bile kolayca okumanızı sağlar.

Hata Yönetimi ve Kaynak Kapatma

CSV okuma işlemleri sırasında IOException (dosya bulunamadı, okuma izni yok vb.) veya CsvValidationException (CSV formatı kurallarına uymayan veri) gibi hatalar meydana gelebilir. Bu hataları yakalamak ve uygun şekilde işlemek uygulamanızın sağlamlığı için kritik öneme sahiptir.

Yukarıdaki örneklerde gösterildiği gibi, try-with-resources yapısı CSVReader ve FileReader gibi kaynakların işleri bittiğinde veya bir hata oluştuğunda otomatik olarak kapatılmasını garanti eder. Bu, kaynak sızıntılarını önlemenin en iyi yoludur.

try (CSVReader reader = new CSVReader(new FileReader(dosyaYolu))) {
    // Okuma işlemleri
} catch (IOException e) {
    System.err.println("Dosya erişim hatası: " + e.getMessage());
} catch (CsvValidationException e) {
    System.err.println("CSV veri doğrulama hatası: " + e.getMessage());
}

CSVWriter ile CSV Dosyalarına Yazma

CSVWriter sınıfı, OpenCSV'nin CSV dosyalarına veri yazma bileşenidir. CSVReader gibi, CSVWriter da çeşitli konfigürasyon seçenekleriyle esnek yazma yetenekleri sunar.

Temel CSV Yazma İşlemleri

CSVWriter, bir Writer nesnesi (örneğin, FileWriter) alır ve String[] formatındaki verileri CSV dosyasına yazar.

1. Satır Satır Yazma (Line by Line):

writeNext() metodu, tek bir String[] dizisini CSV formatında bir satır olarak dosyaya yazar.

import com.opencsv.CSVWriter;

import java.io.FileWriter;
import java.io.IOException;

public class CsvWriterTemelOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "yeni_veri.csv";

        String[] baslik = {"Ad", "Soyad", "Yaş", "Şehir"};
        String[] veri1 = {"Can", "Yılmaz", "28", "İstanbul"};
        String[] veri2 = {"Zeynep", "Kara", "32", "Ankara"};
        String[] veri3 = {"Ahmet", "Ak", "45", "İzmir"};
        String[] veri4 = {""Merhaba, Dünya"", "Özel", "10", "Gezegen"}; // Virgül içeren veri

        try (CSVWriter writer = new CSVWriter(new FileWriter(dosyaYolu))) {
            writer.writeNext(baslik);
            writer.writeNext(veri1);
            writer.writeNext(veri2);
            writer.writeNext(veri3);
            writer.writeNext(veri4);

            System.out.println(dosyaYolu + " dosyasına veri başarıyla yazıldı.");

        } catch (IOException e) {
            System.err.println("CSV yazma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

yeni_veri.csv içeriği:

Ad,Soyad,Yaş,Şehir
Can,Yılmaz,28,İstanbul
Zeynep,Kara,32,Ankara
Ahmet,Ak,45,İzmir
"""Merhaba, Dünya""",Özel,10,Gezegen

Dikkat edin: "Merhaba, Dünya" ifadesi OpenCSV tarafından otomatik olarak """Merhaba, Dünya""" şeklinde yazıldı. İlk ve son tırnaklar alanın tırnak içine alındığını belirtirken, içindeki tırnaklar kaçış karakteri olarak çift tırnakla temsil edildi. Bu, CSV standartlarına uygun bir davranıştır.

2. Tüm Satırları Bir Kerede Yazma:

writeAll() metodu, List tipindeki tüm verileri tek seferde dosyaya yazar. Bu, özellikle bellekte zaten hazır olan küçük veri kümeleri için kullanışlıdır.

import com.opencsv.CSVWriter;

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

public class CsvWriterReadAllOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "tum_yeni_veri.csv";

        List veriListesi = new ArrayList<>();
        veriListesi.add(new String[]{"Ürün Kodu", "Ürün Adı", "Fiyat", "Stok"});
        veriListesi.add(new String[]{"P001", "Laptop", "1200.50", "50"});
        veriListesi.add(new String[]{"P002", "Mouse", "25.99", "200"});
        veriListesi.add(new String[]{"P003", "Klavye", "75.00", "150"});

        try (CSVWriter writer = new CSVWriter(new FileWriter(dosyaYolu))) {
            writer.writeAll(veriListesi);
            System.out.println(dosyaYolu + " dosyasına tüm veri başarıyla yazıldı.");

        } catch (IOException e) {
            System.err.println("CSV yazma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Gelişmiş CSV Yazma Konfigürasyonları

CSVWriterBuilder sınıfı, CSVWriter'ın davranışını özelleştirmek için kullanılır.

1. Özel Ayırıcı, Tırnak ve Kaçış Karakterleri Kullanımı:

CSVWriterBuilder ile ayırıcı, tırnak karakteri ve kaçış karakterini belirleyebilirsiniz. Bu, belirli bir formatta CSV dosyası oluşturmanız gerektiğinde faydalıdır.

import com.opencsv.CSVWriter;
import com.opencsv.CSVWriterBuilder;
import com.opencsv.ICSVWriter; // Sabitleri içerir

import java.io.FileWriter;
import java.io.IOException;

public class CsvWriterOzelKonfigurasyonOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "ozel_format_veri.csv";

        String[] baslik = {"ID", "Açıklama", "Değer"};
        String[] veri1 = {"1", "Bu bir açıklama; noktalı virgül içerir", "100"};
        String[] veri2 = {"2", "Başka bir açıklama", "200"};

        try (CSVWriter writer = new CSVWriterBuilder(new FileWriter(dosyaYolu))
                .withSeparator(';') // Noktalı virgül ayırıcı
                .withQuoteChar('\'') // Tek tırnak karakteri
                .withEscapeChar('\\') // Ters eğik çizgi kaçış karakteri
                .withLineEnd(ICSVWriter.RFC4180_LINE_END) // Satır sonu karakteri (varsayılan)
                .build()) {

            writer.writeNext(baslik);
            writer.writeNext(veri1);
            writer.writeNext(veri2);

            System.out.println(dosyaYolu + " dosyasına özel formatta veri yazıldı.");

        } catch (IOException e) {
            System.err.println("CSV yazma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

ozel_format_veri.csv içeriği:

'ID';'Açıklama';'Değer'
'1';'Bu bir açıklama\; noktalı virgül içerir';'100'
'2';'Başka bir açıklama';'200'

Yukarıdaki örnekte, noktalı virgül içeren alan otomatik olarak tek tırnak içine alınmış ve içindeki noktalı virgül kaçış karakteriyle (\) belirtilmiştir.

2. Mevcut Dosyaya Ekleme (Appending):

Mevcut bir CSV dosyasına yeni satırlar eklemek isterseniz, FileWriter'ı true parametresiyle (append modu) oluşturmanız ve CSVWriter'a vermeniz yeterlidir.

import com.opencsv.CSVWriter;

import java.io.FileWriter;
import java.io.IOException;

public class CsvWriterAppendOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "mevcut_veri.csv"; // Bu dosyanın önceden var olduğunu varsayalım

        // İlk çalıştırmada bir dosya oluşturalım (eğer yoksa)
        try (CSVWriter writer = new CSVWriter(new FileWriter(dosyaYolu))) {
            writer.writeNext(new String[]{"Ürün", "Miktar"});
            writer.writeNext(new String[]{"Elma", "100"});
        } catch (IOException e) { / Hata yönetimi / }

        // Şimdi mevcut dosyaya ekleyelim
        String[] yeniVeri1 = {"Armut", "50"};
        String[] yeniVeri2 = {"Muz", "75"};

        try (CSVWriter writer = new CSVWriter(new FileWriter(dosyaYolu, true))) { // true = append modu
            writer.writeNext(yeniVeri1);
            writer.writeNext(yeniVeri2);
            System.out.println(dosyaYolu + " dosyasına yeni veriler eklendi.");
        } catch (IOException e) {
            System.err.println("CSV ekleme hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

mevcut_veri.csv içeriği (ekleme sonrası):

Ürün,Miktar
Elma,100
Armut,50
Muz,75

Hata Yönetimi ve Kaynak Kapatma

Yazma işlemlerinde de IOException hataları meydana gelebilir (disk dolu, yazma izni yok vb.). try-with-resources yine en iyi pratik olup, CSVWriter ve FileWriter kaynaklarının otomatik olarak kapatılmasını sağlar. Ayrıca, writer.flush() metodunu çağırarak tamponlanan verilerin dosyaya yazıldığından emin olabilirsiniz, ancak try-with-resources bunu otomatik olarak halleder.

try (CSVWriter writer = new CSVWriter(new FileWriter(dosyaYolu))) {
    // Yazma işlemleri
} catch (IOException e) {
    System.err.println("Dosya yazma hatası: " + e.getMessage());
}

Nesne Haritalama (Object Mapping) ile Daha Kolay CSV İşlemleri

OpenCSV'nin en güçlü özelliklerinden biri, CSV verilerini doğrudan Java nesnelerine dönüştürme (okuma) ve Java nesnelerini CSV formatına dönüştürme (yazma) yeteneğidir. Bu, kodunuzu daha okunabilir, tip güvenli ve sürdürülebilir hale getirir. Bu işlem için CsvToBean, CsvToBeanBuilder ve StatefulBeanToCsv, StatefulBeanToCsvBuilder sınıfları kullanılır.

Öncelikle, CSV verilerini temsil edecek basit bir Java sınıfı (POJO - Plain Old Java Object) tanımlayalım:

public class Musteri {
    private String ad;
    private String soyad;
    private int yas;
    private String sehir;

    // Varsayılan kurucu metot (OpenCSV için gereklidir)
    public Musteri() {
    }

    public Musteri(String ad, String soyad, int yas, String sehir) {
        this.ad = ad;
        this.soyad = soyad;
        this.yas = yas;
        this.sehir = sehir;
    }

    // Getter ve Setter metotları
    public String getAd() { return ad; }
    public void setAd(String ad) { this.ad = ad; }
    public String getSoyad() { return soyad; }
    public void setSoyad(String soyad) { this.soyad = soyad; }
    public int getYas() { return yas; }
    public void setYas(int yas) { this.yas = yas; }
    public String getSehir() { return sehir; }
    public void setSehir(String sehir) { this.sehir = sehir; }

    @Override
    public String toString() {
        return "Musteri{" +
               "ad='" + ad + '\'' +
               ", soyad='" + soyad + '\'' +
               ", yas=" + yas +
               ", sehir='" + sehir + '\'' +
               '}';
    }
}

CSVReader ile Java Nesnelerine Okuma

CsvToBeanBuilder sınıfı, CSVReader ile okunan verileri Musteri gibi bir Java nesnesine dönüştürmek için kullanılır. İki ana strateji vardır:

1. HeaderColumnNameMappingStrategy (Başlık Adlarına Göre Haritalama):

Bu strateji, CSV dosyasının başlık satırındaki sütun adlarını Java sınıfının alan adlarıyla eşleştirir. Bu, en esnek ve okunabilir yöntemdir.

import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CsvToBeanBaslikHaritalamaOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri.csv"; // Başlık satırı içeren dosya

        try (FileReader reader = new FileReader(dosyaYolu)) {
            HeaderColumnNameMappingStrategy strategy = new HeaderColumnNameMappingStrategy<>();
            strategy.setType(Musteri.class);

            CsvToBean csvToBean = new CsvToBeanBuilder(reader)
                    .withType(Musteri.class)
                    .withMappingStrategy(strategy)
                    .build();

            List musteriler = csvToBean.parse();

            for (Musteri musteri : musteriler) {
                System.out.println(musteri);
            }

        } catch (IOException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Çıktı:

Musteri{ad='Ali', soyad='Can', yas=30, sehir='Ankara'}
Musteri{ad='Ayşe', soyad='Yılmaz', yas=25, sehir='İstanbul'}
Musteri{ad='Mehmet', soyad='Demir', yas=40, sehir='İzmir'}
Musteri{ad='Fatma,Gül', soyad='35', yas=0, sehir='Bursa'} // Hata: '35' soyad değil yaş olmalıydı.

Önemli Not: Yukarıdaki çıktıda "Fatma,Gül" satırında bir hata oluştuğunu fark edeceksiniz. Bunun nedeni, veri.csv dosyasındaki "Fatma,Gül",35,Bursa" satırında "35" değerinin soyad alanına karşılık gelmesi ve yas alanının boş kalmasıdır. OpenCSV, int gibi ilkel tipler için varsayılan değer (0) atar. Bu tür durumlarda, CsvBindByName veya CsvBindByPosition gibi anotasyonlar kullanarak haritalamayı daha hassas hale getirebiliriz.

Musteri sınıfını anotasyonlarla güncelleyelim:

import com.opencsv.bean.CsvBindByName; // Başlık adına göre bağlama
import com.opencsv.bean.CsvBindByPosition; // Pozisyona göre bağlama (isteğe bağlı)

public class Musteri {
    @CsvBindByName(column = "Ad")
    private String ad;
    @CsvBindByName(column = "Soyad")
    private String soyad;
    @CsvBindByName(column = "Yaş")
    private int yas;
    @CsvBindByName(column = "Şehir")
    private String sehir;

    // ... (Kurucular, Getter/Setter, toString metotları aynı kalır)
}

Anotasyonları ekledikten sonra, CsvToBeanBaslikHaritalamaOrnek kodunu tekrar çalıştırırsak, çıktı doğru olacaktır:

Musteri{ad='Ali', soyad='Can', yas=30, sehir='Ankara'}
Musteri{ad='Ayşe', soyad='Yılmaz', yas=25, sehir='İstanbul'}
Musteri{ad='Mehmet', soyad='Demir', yas=40, sehir='İzmir'}
Musteri{ad='Fatma,Gül', soyad='35', yas=0, sehir='Bursa'} // Hata hala var!

Hata hala devam ediyor, çünkü veri.csv dosyasında Fatma,Gül alanı çift tırnak içinde olduğu için OpenCSV bunu tek bir alan olarak algılıyor: "Fatma,Gül". Geri kalan 35 ve Bursa ise sırasıyla soyad ve yas alanlarına denk geliyor. Bu durumda yas alanına 35 değeri atanırken, sehir alanı Bursa oluyor ve soyad alanı boş kalıyor (veya 35 değeri string olarak atanıp yas 0 oluyor).

Doğru veri.csv satırı "Fatma,Gül" için:

Ad,Soyad,Yaş,Şehir
Ali,Can,30,Ankara
Ayşe,Yılmaz,25,İstanbul
Mehmet,Demir,40,İzmir
"Fatma","Gül",35,Bursa  // Eğer Fatma ve Gül ayrı alanlarsa

Veya eğer "Fatma,Gül" tek bir alan ise ve yaş 35 ise:

"Fatma,Gül",Bilinmiyor,35,Bursa // "Bilinmiyor" soyad için bir yer tutucu

Basitlik adına, veri.csv dosyasını şu şekilde güncelleyelim ki, HeaderColumnNameMappingStrategy doğru çalışsın:

Ad,Soyad,Yaş,Şehir
Ali,Can,30,Ankara
Ayşe,Yılmaz,25,İstanbul
Mehmet,Demir,40,İzmir
Fatma,Gül,35,Bursa

Bu durumda "Fatma,Gül" satırı artık sorun yaratmayacaktır, çünkü virgül tırnak içinde değil. Eğer gerçekten "Fatma,Gül" tek bir isimse, o zaman CSV'de "Fatma,Gül",Soyad,Yaş,Şehir şeklinde yazılması ve Musteri sınıfında ad alanının bu tek değeri alması gerekir. Mevcut Musteri sınıfımızda ad ve soyad ayrı alanlar olduğu için, bu CSV yapısı daha uygun.

Tekrar çalıştırdığımızda çıktı şöyle olacaktır:

Musteri{ad='Ali', soyad='Can', yas=30, sehir='Ankara'}
Musteri{ad='Ayşe', soyad='Yılmaz', yas=25, sehir='İstanbul'}
Musteri{ad='Mehmet', soyad='Demir', yas=40, sehir='İzmir'}
Musteri{ad='Fatma', soyad='Gül', yas=35, sehir='Bursa'}

Bu, beklenen doğru çıktıdır.

2. ColumnPositionMappingStrategy (Sütun Pozisyonuna Göre Haritalama):

Bu strateji, CSV dosyasının sütunlarının pozisyonlarını Java sınıfının alanlarıyla eşleştirir. CSV dosyasında başlık satırı yoksa veya sütun adları garanti edilmiyorsa kullanışlıdır. Anotasyon olarak CsvBindByPosition kullanılır.

Musteri sınıfını pozisyonlara göre güncelleyelim:

import com.opencsv.bean.CsvBindByPosition;

public class Musteri {
    @CsvBindByPosition(position = 0)
    private String ad;
    @CsvBindByPosition(position = 1)
    private String soyad;
    @CsvBindByPosition(position = 2)
    private int yas;
    @CsvBindByPosition(position = 3)
    private String sehir;

    // ... (Kurucular, Getter/Setter, toString metotları aynı kalır)
}

Okuma kodu:

import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.ColumnPositionMappingStrategy;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CsvToBeanPozisyonHaritalamaOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "veri.csv"; // Başlık satırı içeren dosya

        try (FileReader reader = new FileReader(dosyaYolu)) {
            ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy<>();
            strategy.setType(Musteri.class);

            // Eğer başlık satırını atlamak istiyorsak, reader'ı ona göre yapılandırmalıyız.
            // Bu örnekte, başlık satırını atlamadan pozisyonlara göre okuyacağız,
            // bu da başlık satırını da Musteri nesnesine dönüştürmeye çalışacağı anlamına gelir.
            // Gerçek uygulamalarda başlık satırı atlanmalıdır.
            
            CsvToBean csvToBean = new CsvToBeanBuilder(reader)
                    .withType(Musteri.class)
                    .withMappingStrategy(strategy)
                    .withSkipLines(1) // Başlık satırını atla
                    .build();

            List musteriler = csvToBean.parse();

            for (Musteri musteri : musteriler) {
                System.out.println(musteri);
            }

        } catch (IOException e) {
            System.err.println("CSV okuma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Çıktı (yine güncellenmiş veri.csv ile):

Musteri{ad='Ali', soyad='Can', yas=30, sehir='Ankara'}
Musteri{ad='Ayşe', soyad='Yılmaz', yas=25, sehir='İstanbul'}
Musteri{ad='Mehmet', soyad='Demir', yas=40, sehir='İzmir'}
Musteri{ad='Fatma', soyad='Gül', yas=35, sehir='Bursa'}

withSkipLines(1) kullanılması, başlık satırının Musteri nesnesine dönüştürülmeye çalışılmasını engeller ve sadece veri satırlarının işlenmesini sağlar.

CSVWriter ile Java Nesnelerinden Yazma

StatefulBeanToCsvBuilder sınıfı, Java nesnelerinin listesini CSV formatına yazmak için kullanılır. Bu da Musteri sınıfımızdaki anotasyonları kullanır.

import com.opencsv.CSVWriter;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;

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

public class BeanToCsvOrnek {

    public static void main(String[] args) {
        String dosyaYolu = "musteri_listesi.csv";

        List musteriler = new ArrayList<>();
        musteriler.add(new Musteri("Elif", "Kaya", 22, "Antalya"));
        musteriler.add(new Musteri("Burak", "Aslan", 38, "Konya"));
        musteriler.add(new Musteri("Gizem", "Deniz", 29, "Trabzon"));

        try (FileWriter writer = new FileWriter(dosyaYolu)) {
            HeaderColumnNameMappingStrategy strategy = new HeaderColumnNameMappingStrategy<>();
            strategy.setType(Musteri.class);

            StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
                    .withMappingStrategy(strategy)
                    .withSeparator(CSVWriter.DEFAULT_SEPARATOR) // Varsayılan virgül
                    .withQuoteChar(CSVWriter.DEFAULT_QUOTE_CHARACTER) // Varsayılan çift tırnak
                    .build();

            beanToCsv.write(musteriler);

            System.out.println(dosyaYolu + " dosyasına müşteri listesi başarıyla yazıldı.");

        } catch (IOException | CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
            System.err.println("CSV yazma hatası: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

musteri_listesi.csv içeriği:

Ad,Soyad,Yaş,Şehir
Elif,Kaya,22,Antalya
Burak,Aslan,38,Konya
Gizem,Deniz,29,Trabzon

StatefulBeanToCsvBuilder varsayılan olarak başlık satırını da yazar. HeaderColumnNameMappingStrategy kullanıldığı için, başlıklar Musteri sınıfındaki @CsvBindByName anotasyonlarında belirtilen column adlarından veya alan adlarından (anotasyon yoksa) alınır.

OpenCSV ile En İyi Uygulamalar ve Performans İpuçları

OpenCSV'yi kullanırken dikkate almanız gereken bazı en iyi uygulamalar ve performans ipuçları:

1. Kaynak Yönetimi (try-with-resources): Her zaman CSVReader, CSVWriter, FileReader ve FileWriter gibi kaynakları try-with-resources bloğu içinde kullanın. Bu, kaynakların otomatik olarak kapatılmasını sağlayarak bellek sızıntılarını ve dosya kilitleme sorunlarını önler.
2. Büyük Dosyalar İçin Bellek Yönetimi:
* Okuma: Çok büyük CSV dosyalarını okurken CSVReader.readAll() yerine CSVReader.readNext() metodunu bir döngü içinde kullanın. Bu, tüm dosyanın içeriğinin belleğe yüklenmesini engeller ve bellek taşması (OutOfMemoryError) riskini azaltır.
* Yazma: Benzer şekilde, büyük veri kümelerini yazarken CSVWriter.writeNext() metodunu satır satır kullanın.
3. Karakter Kodlaması (UTF-8): Özellikle Türkçe karakterler veya uluslararası karakterler içeren CSV dosyalarıyla çalışırken karakter kodlamasını belirtmek önemlidir. FileReader veya FileWriter yerine InputStreamReader ve OutputStreamWriter kullanarak karakter kodlamasını (örneğin, StandardCharsets.UTF_8) açıkça belirtebilirsiniz.

// Okuma
    try (CSVReader reader = new CSVReader(new InputStreamReader(new FileInputStream(dosyaYolu), StandardCharsets.UTF_8))) {
        // ...
    }

    // Yazma
    try (CSVWriter writer = new CSVWriter(new OutputStreamWriter(new FileOutputStream(dosyaYolu), StandardCharsets.UTF_8))) {
        // ...
    }

4. Hata Yönetimi: IOException, CsvValidationException, CsvDataTypeMismatchException gibi istisnaları uygun şekilde yakalayın ve kullanıcılara anlamlı geri bildirim sağlayın veya loglama yapın.
5. Boş Satırları ve Alanları Yönetme: OpenCSV, boş satırları ve alanları varsayılan olarak doğru şekilde işler. Ancak, uygulamanızın özel gereksinimleri varsa, CSVReaderBuilder veya CsvToBeanBuilder üzerindeki withIgnoreEmptyLines() gibi metotları veya özel dönüştürücüleri kullanabilirsiniz.
6. Performans Optimizasyonu (Yazma): Büyük dosyalar yazarken, CSVWriter'ın dahili bir tamponu vardır. Daha iyi performans için writer.flush() metodunu periyodik olarak çağırabilirsiniz (ancak try-with-resources bloğu sonunda otomatik olarak kapanırken bu çağrı yapılır).

Sonuç

OpenCSV kütüphanesi, Java geliştiricileri için CSV dosyalarını okuma ve yazma işlemlerini önemli ölçüde basitleştiren güçlü ve esnek bir araçtır. CSVReader ve CSVWriter sınıfları aracılığıyla temel okuma/yazma işlemlerinden, CSVReaderBuilder ve CSVWriterBuilder ile gelişmiş konfigürasyonlara kadar geniş bir yelpazede işlevsellik sunar.

Özellikle CsvToBean ve StatefulBeanToCsv ile sunulan nesne haritalama yeteneği, CSV verilerini Java nesneleriyle doğrudan eşleştirerek kodun okunabilirliğini, bakımını ve tip güvenliğini artırır. Bu özellik, iş mantığını veri ayrıştırma detaylarından ayırarak geliştiricilerin daha karmaşık işlevselliklere odaklanmasını sağlar.

Bu makalede sunulan örnekler ve açıklamalar, OpenCSV'yi projelerinize entegre etmek ve CSV işleme görevlerini verimli bir şekilde yerine getirmek için sağlam bir temel sağlamıştır. Doğru kullanım ve en iyi uygulamalarla OpenCSV, veri alışverişi gereksinimleriniz için vazgeçilmez bir araç haline gelecektir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Mobil sürümden çık