package javacodebook.io.copyfile;

import java.io.*;

/**
 *
 *  Kopieren einer Datei von a nach b.
 *  Zur Vereinfachung wird die Methode copyFile überladen, so dass sie einmal mit zwei
 *  Strings für die Dateinamen aufgerufen werden kann, oder direkt mit den entsprechenden
 *  File-Objekten.
 *
 * @author  Dirk Brodersen
 */
public class CopyFile {

    public static void copyFile(String sourceFileName, String targetFileName)
    throws IOException {
        File sourceFile = new File(sourceFileName);
        File targetFile = new File(targetFileName);
        copyFile(sourceFile, targetFile);
    }

    public static void copyFile(File sourceFile, File targetFile)
    throws IOException {
        //Überprüfen, ob die zu kopierende Datei überhaupt existiert oder ein Verzeichnis ist
        if(!sourceFile.exists())
            throw new IOException("Die zu kopierende Datei existiert nicht!");
        else if(sourceFile.isDirectory())
            throw new IOException("Quelldatei ist ein Verzeichnis");

        //Überprüfen, ob die Zieldatei existiert bzw. ein Verzeichnis angegeben wurde
        if(targetFile.exists()) {
            if(targetFile.isFile()) {
                if(!targetFile.canWrite())
                    throw new IOException("Die Zieldatei existiert und ist schreibgeschützt!");
            }
            //Ist die Zieldatei ein Verzeichnis, so wird der Name der Quelldatei extrahiert
            //und an das Zielverzeichnis angehängt.
            else {
                String fileName = sourceFile.getName();
                //Der komplette Pfad des Zielverzeichnisses + der Dateiname der Quelldatei ergeben
                //die Zieldatei. Dabei wird die Plattformunabhängigkeit gewährleistet, indem
                //File.separator verwendet wird statt "\" für Windows bzw. "/" für Unix
                targetFile = new File(targetFile.getAbsolutePath() + File.separator + fileName);
                if(targetFile.exists() && !targetFile.canWrite())
                    throw new IOException("Im Zielverzeichnis existiert bereits eine schreibgeschützte Datei gleichen Namens");
            }

        }
        //Die Datei existiert, jetzt kann sie kopiert werden

        //Ein Puffer wird definiert, damit die Datei in effizienten Stücken kopiert wird.
        int bufferSize = 16384;
        byte[] buffer = new byte[bufferSize];

        //Ein InputStream für den lesenden und ein OutputStream für den schreibenden Zugriff
        InputStream in = new FileInputStream(sourceFile);
        OutputStream out = new FileOutputStream(targetFile);

        //Die Anzahl der in jedem Schritt gelesenen Bytes wird vermerkt. Das ist wichtig, damit
        //am Ende der Datei keine überflüssigen Nullbytes angehängt werden
        int bytes = 0;

        //Hier erfolgt der eigentliche Kopiervorgang. Es wird so lange auf den InputStream
        //zugegriffen, bis keine Daten mehr gelesen werden, also das Ende der Datei erreicht ist.
        //Die gelesenen Bytes werden in das Array buffer zwischengespeichert, von wo aus sie
        //in den OutputStream geschrieben werden.
        while((bytes = in.read(buffer)) > 0) {
            out.write(buffer,0, bytes);
        }
        in.close();
        out.close();
    }

    public static void main(String[] args) {
        try {
            System.out.print("Quelldatei: ");
            String sourceFile = new BufferedReader(new InputStreamReader(System.in)).readLine();
            System.out.print("Ziel: ");
            String targetFile = new BufferedReader(new InputStreamReader(System.in)).readLine();
            copyFile(sourceFile, targetFile);
            System.out.println("Datei wurde kopiert");
        }
        catch(IOException e) {
            e.printStackTrace(System.out);
        }
    }
}
