İçindekilerGirişİndex
YukarıİlkÖncekiSonrakiSon
Geriİleri
Yazdır
Onder Teker
on_der_tek_er@yahoo.com

Dosya Tabanlı Veritabanı Örneği

Bu örnek Student ve School şeklinde iki class içeriyor. Bir okulun öğrencileri diskte bir dosyada saklanıyor. Program açılırken öğrenci kayıtlı dosyadan okunuyor ve program sonunda da değişiklikler sonrasındaki öğrenciler saklanıyor. Dosya CSV (Comma Separated Vector) denilen bir yapıda saklanıyor. Bu formatta her kayıt bir satıra denk düşüyor. Her satır da ';' (veya tab [\t] ) karakteriyle ayrılarak yazılıyor. Dosyadakı her satır bir öğrencininn bilgisini tutuyor. Tüm dosya da okuldaki bütün bilgileri. Bu şekilde bir SQL Server olmadan, basit bir biçimde veri tabanı işlemleri yapılabilir. Ancak sorgulama işleri biraz zor olur ve performans son derece düşük olur. Buna karşın basitliği Excel gibi spreedsehht uygulamalarıyla entegrasyonu sayesinde bazı yerlerde kullanılabilmektedir.

Student Class'ı

Bu class bir öğrencide bulunabilecek bazı property'leri içeriyor. Bu property'ler duruma göre değişebilir. Her bir property için set ve get method'ları yazılmış.

public class Student {

	private String id="";
	private String name="";
	private int grade=0;
	private float average=0;

  public Student() {
  }
  public Student(String id,String name,int grade) {
		setId(id);
		setName(name);
		setGrade(grade);
  }
	public String getId(){
		return id;
	}
	public void setId(String id){
		this.id=id;
	}
	public String getName(){
		return this.name;
	}
	public void setName(String name){
		this.name=name;
	}
	public int getGrade(){
		return grade;
	}
	public void setGrade(int grade){
		this.grade=grade;
	}
	public int getAverage(){
		return grade;
	}
	public void setAverage(float average){
		this.average=average;
	}
}

Parse & Format

Student class'ında property ve methodlar dışında static olarak tanımlanmış format ve parse method'ları var. Bunlar başka bir class'da (örneğin School'da) da olabilirdi. format(), property'leri string'e çevirerek ';' delimiter'ıyla birleştiriyor. Her tipin (primitive veya class tipinin) ayrı bir şekilde string'e dönüştürme yöntemi vardır. Primitive tipler wrapper class'ların (int için Integer gibi) toString() methodlarını içerir. Ancak her tip için durum böyle değildir Date için bir DateFormat kullanmak gerekir örneğin. Kendi yaptığımız class'ların toString() methodunu kendimiz yazarız.

public static String format(Student student){
  StringBuffer buffer=new StringBuffer();// New!
  String id=student.getId();
  buffer.append(id+";");
  String name=student.getName();
  buffer.append(name+";");
  int grade=student.getGrade();
  String gradeString=Integer.toString(grade);
  buffer.append(gradeString+";");
  float average=student.getAverage();
  String averageString=Float.toString(average);
  buffer.append(averageString);
  String line=buffer.toString();
  return line;
}

Format'larken StringBuffer kullanılması performansı arttırır. Bu class'daki append metodu yerine String'ler için concat (+) operatörü kullanılırsa her concat sonrasında yeni bir String nesnesi yaratılılır. Oysa burada sadece bir tek StringBuffer nesnesi kullanılıyor.

Parse ederken StringTokenizer kullanılıyor. Ancak bir while döngüsü yerine property kadar nextToken() çağrılıyor. Çünkü her satırı biz yazdığımız için içinde ne kadar token (field) olduğunu biliyoruz.

public static Student parse(String line){
    StringTokenizer tokenizer=new StringTokenizer(line,";");
    String id=tokenizer.nextToken();
    String name=tokenizer.nextToken();
    String gradeString=tokenizer.nextToken();
    int grade=Integer.parseInt(gradeString);
    String averageString=tokenizer.nextToken();
    float average=Float.parseFloat(averageString);
    Student student=new Student(id,name,grade);
    student.setAverage(average);
    return student;
  }

School Class'ı

Bu class bir Hashtable'da Student nesnelerini tutuyor. Buradaki addStudent methodu, Student class'ını, 'id' field'ını key olarak kullanarak Hashtable'a koyuyor. containsStudent method'u verilen id'li Student'in School'da bulunup bulunmadığını kontorl ediyor. Bir student eklerken böyle bir konrol yapılmasının nedeni yanlışlıkla aynı id ile başka bir student eklenmesini önlemek. Bu kontrol yapılmazsa önceki öğrenci ezilir. Aynı kontol'ü (daha doğrusu tersini) removeStudent'ta da yaptık. Olmayan bir student'ın yanlışlıkla school'dan çıkarılmasının engellemek için.

  public class School {
  
    private Hashtable students=new Hashtable();
  
    public School() {
    }
    public void addStudent(Student student){
      String id=student.getId();
      if(!containsStudent(id)){
        students.put(id,student);
      }else{
        throw new IllegalArgumentException("Student already exists : "+id);
      }
    }
    public boolean containsStudent(String id){
      return getStudent(id)!=null;
    }
    public void removeStudent(String id){
      if(containsStudent(id)){
        students.remove(id);
      }else{
        throw new IllegalArgumentException("Student not found : "+id);
      }
  
    }
    public Student getStudent(String id){
      return (Student) students.get(id);
    }
    public Hashtable getStudents(){
      return students;
    }
  
  }

Load ve Store

School class'ıda student'ları bir dosyaya kaydetmek için store diye bir method var. Burada bir dosya açılıyor, öğrenciler tek tek alınıyor, format() method'uyla satır biçiminde string'e dönüştürülüyor ve Writer'la yazılıyor.

  public void store(File file)
      throws IOException
  {
    FileWriter fw=new FileWriter(file);
    BufferedWriter out=new BufferedWriter(fw);
    Enumeration e=students.keys();
    while(e.hasMoreElements()){
      String id=(String) e.nextElement();
      Student student=getStudent(id);
      String line=Student.format(student);
      out.write(line+"\r\n");
    }
    out.close();
  }

Load method'u store'un tersini, yani diskteki kayıtların hafızadaki nesnelere dönüşmesini sağlıyor. Burada da Student class'ının static method'u parse() kullanılıyor.

  public void load(File file)
      throws IOException
  {
    FileReader fr=new FileReader(file);
    BufferedReader in=new BufferedReader(fr);
    String line=null;
    while((line=in.readLine())!=null){
      Student student=Student.parse(line);
      addStudent(student);
    }
    in.close();
  }

methodu yazılmış. Bu method tek tek bütün student'leri alıyor, grade'i verilen grade'e eşit olanları bir Vector'e koyup döndürüyor.

Aynı şekilde findAboveAvaregeStudents methodu'da belli bir ortalamanın üzerindeki öğrencileri buluyor.

  public Vector findAboveAvaregeStudents(float average){
    Vector results=new Vector();
    Enumeration e=students.elements();
    while(e.hasMoreElements()){
      Student student=(Student) e.nextElement();
      if(student.getAverage()>=average){
        results.add(student);
      }
    }
    return results;
  }

Test

School class'ındaki main method'u yazılan kodu test etmektedin. Doğrudan veya dolaylı olarak kullanılan mehtod'lar hemen hemen bütün kodun testini yapmaktadır.

  public static void main(String[] args)
      throws Exception
  {
    File file=new File("School.txt");
    School school=new School();
    if(file.exists()){
      school.load(file);
    }
    Student student=new Student("1244","Orhan Gencebay",2);
    school.addStudent(student);
    school.store(file);
  }

Burada School class'ı yaratılmakta ve bir file'dan load edilmektedir. İlk açıldığında file olmayabilir o yüzden bir kontrol kondu. Bir Student yaratılmakta ve School'a eklenmektedir. Daha sonra store methodu çağrılarak değişikliğin kaydedilmesi sağlanır.

Main'de sorgulamalardan birnin testi de yapılmıştır. Grade'i 2 olan student'lar bulunmakta ve isimleri ekrana yazılmaktadır.

  Vector vector=school.findGradeStudents(2); 
  for(int i=0;i<vector.size();i++){
    Student result=(Student) vector.get(i); 
    String name=result.getName(); 
    System.out.println("Name "+name); 
  } 

Java Dosyaları

Dosyalar içlerinde belirtiler package'lere uygun klasörlere konulmalı

İçindekilerGirişİndex
YukarıİlkÖncekiSonrakiSon
Geriİleri
Yazdır