среда, 1 августа 2012 г.

core-labs: io


Java I/O


    File API
        - io.file.look_for_new_big_image (обязательно)
        - io.file.copy_dir (обязательно)
        - io.file.random_access

    Charset
        - ???



    File API



    io.file.look_for_new_big_image

    Этот пример кода - проходит по всей директории (включая вложенные) и выводит имена всех файлов в консоль
import java.io.File;

public class FileLab_LookFor {
    public static void main(String[] args) {
        File file = new File("d:/tmp");
        print(file);
    }
    
    public static void print(File root) {
        if (root.isFile()) {
            System.out.println(root);
        } else {
            File[] fileArray = root.listFiles();
            for (File file : fileArray) {
                print(file);
            }
        }        
    }
}
    Модифицируйте/допишите его, что бы он
    1) Собирал только имена файлов, которые представляют собой большие (File.length() > 1024*1024) картинки (имя файла заканчивается (String.endsWith(String)) на ".jpg"/".png"/".bmp"/".gif".
    2) Собирал массив файлов, а не выводил в консоль.
    3) Для реализации пункта 1 рекомендуется (но не обязательно) использовать FileFilter
public class FileLab_LookFor {
    public static void main(String[] args) {
        File[] bigImages = lookForBigImage(new File("d:/tmp"));
    }

    public static File[] lookForBigImage(File root) {...}
}
    Вам может помочь метод 
    public static File[] concatenate(File[] file0, File[] file1) {
        File[] result = new File[file0.length + file1.length];
        System.arraycopy(file0, 0, result, 0, file0.length);
        System.arraycopy(file1, 0, result, file0.length, file1.length);
        return result;
    }

    io.file.copy_dir

    Данный код создает копию структуры папок

import java.io.File;

public class FileLab_CopyDir {
    public static void main(String[] args) {
        copy(new File("d:/tmp"), new File("d:/tmp2"));
    }

    private static void copy(File src, File dst) {
        if (src.isDirectory()) {
            if (!dst.exists()) {
                dst.mkdir();
            }
            for (File srcSubDir : src.listFiles()) {
                String subDirName = srcSubDir.getName();
                copy(srcSubDir, new File(dst, subDirName));
            }
        }
    }
}
    Модифицируйте/допишите код, что бы он создавал не только копию папок, но и копии всех файлов.


    io.file.random_access

    Есть класс Record        
public class Record {
    public static int MAX_DATA_LENGTH = 64;
    private final int id;
    private final byte[] data;

    public Record(int id, byte[] data) {
        if (data == null) {
            throw new IllegalArgumentException("'data' must be not null");
        }
        if (data.length > MAX_DATA_LENGTH) {
            throw new IllegalArgumentException("'data.length' must be less or equals than " + MAX_DATA_LENGTH);
        }
        this.id = id;
        this.data = data;
    }

    public int getId() {
        return id;
    }

    public byte[] getData() {
        return data;
    }
}
который содержит два поля: id типа int и data типа byte[]. Поле дата переменной длины - от 0 до 64 байт. Значение null - недопустимо.

    Вот класс, который "делает" из RandomAccessFile - "хранилище для Record" с произвольным доступом:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RecordStorage implements AutoCloseable {
    private static final int INT_SIZE_IN_BYTES = 4;
    private final RandomAccessFile file;

    public RecordStorage(String fileName) throws FileNotFoundException {
        this.file = new RandomAccessFile(fileName, "rw");
    }

    public void write(Record record, int index) throws IOException {
        // seek to record position in file
        file.seek(index * (INT_SIZE_IN_BYTES + Record.MAX_DATA_LENGTH));
        // write fields
        file.writeInt(record.getId());
        file.write(record.getData());
    }

    public Record read(int index) throws IOException {
        // seek to record position in file
        file.seek(index * (INT_SIZE_IN_BYTES + Record.MAX_DATA_LENGTH));
        // read fields
        int id = file.readInt();
        byte[] data = new byte[Record.MAX_DATA_LENGTH];
        file.readFully(data);
        // return
        return new Record(id, data);
    }

    public void flush() throws IOException {
        file.getChannel().force(true);
        file.getFD().sync();
    }

    @Override
    public void close() throws IOException {
        file.close();
    }
}
    Вот класс, демонстрирующий использование этого хранилища:
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;

public class Application {
    private static final int COUNT = 1000;

    public static void main(String[] args) throws IOException {
        String fileName = "c:/tmp/data.bin";
        initStorageData(fileName);
        testStorageData(fileName);
    }

    private static void initStorageData(String fileName) throws IOException {
        try (RecordStorage storage = new RecordStorage(fileName)) {
            for (int k = 0; k < COUNT; k++) {
                Record newRecord = generateRecord(k);
                storage.write(newRecord, k);
            }
            storage.flush();
        }
    }

    private static void testStorageData(String fileName) throws IOException {
        try (RecordStorage_q storage = new RecordStorage(fileName)) {
            for (int k = COUNT - 1; k >= 0; k--) {
                Record expected = generateRecord(k);
                Record actual = storage.read(k);
                if (actual.getId() != expected.getId()) {
                    throw new AssertionError("k = " + k + ", actual.getId()  = " + actual.getId() + ", expected.getId() = " + expected.getId());
                }
                if (!Arrays.equals(actual.getData(), expected.getData())) {
                    throw new AssertionError("k = " + k + ", \n  actual.getData() = " + Arrays.toString(actual.getData()) + ", \nexpected.getData() = " + Arrays.toString(expected.getData()));
                }
            }
        }
    }

    private static Record generateRecord(int k) {
        Random rnd = new Random(k);
        // random int
        int id = rnd.nextInt();
        // create array of random length
        byte[] data = new byte[rnd.nextInt(Record.MAX_DATA_LENGTH)];
//        byte[] data = new byte[Record.MAX_DATA_LENGTH];
        // fill array by random bytes
        rnd.nextBytes(data);
        return new Record(id, data);
    }
}
    В данном случае, RecordStorage позволяет хранить записи исключительно одинакового размера - 64 байта.
    Задача: изменить RecordStorage для того, что бы можно было раскомментировать красную строчку и закомментировать синюю. Т.е. перейти к записям произвольной длины в диапазоне 0-64 байта. Предлагается в RandomAccessFile сохранять также длину поля Record.getData().


    Charset
xxx
x
xxx
x
xxx
x