ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Camel][Java] RandomAccessFile & File 클래스
    Java/개념 정리 2020. 3. 5. 17:52

    이전 포스팅에서 다뤘던 입출력 스트림은 순차적인 입출력에 한하여 사용가능한 스트림이었습니다. 

    2020/03/03 - [Java] - [Camel][Java] InputStream & OutputStream (파일 입출력)

    2020/03/04 - [Java] - [Camel][Java] 문자 스트림(Stream) / FileReader, FileWriter, BufferedReader, BufferedWriter

    2020/03/05 - [Java] - [Camel][Java] ObjectInputStream & ObjectOutputStream

     

    RandomAccessFile 클래스

     RandomAccessFile 클래스는 순차적이지 않은 형태의 접근이 필요한 경우 사용하게됩니다. 파일의 중간이나 끝에 저장된 데이터를 읽어오고 싶은 경우가 이런 경우에 해당됩니다. 

     

     RandomAccessFile 클래스는 입력과 출력이 동시에 이뤄질 수 있으며, 입출력 위치를 임의로 변경할 수 있습니다. 또한 파일을 대상으로만 존재하는 스트림이라는 특징이 있습니다. 

     

    RandomAccessFile 클래스에 정의되어 있는 대표적인 메소드는 아래와 같습니다. 

    public int read() throws IOException
    public int read(byte[] b, int off, int len) throws IOException
    public final int readInt() throws IOException
    public final double readDouble() throws IOException
    
    public void write(int b) throws IOException
    public void write(byte[] b, int off, int len) throws IOException
    public final void writeInt(int v) throws IOException
    public final void writeDouble(double v) throws IOException

    RandomAccessFile 클래스는 위의 대표 메소드를 확인하면 알 수 있듯이 Byte단위와 기본자료형 단위의 데이터 입출력이 가능합니다. 그리고 아래의 메소드를 사용해 현재으 입출력 위치를 확인하거나 변경할 수 있습니다. 

    public long getFilePointer() throws IOException
    public void seek(long position) throws IOException

     

    RandomAccessFile 예제 코드

    import java.io.*;
    
    class RAF {
    	public static void main ( String[] args ) {
        	
            	RandomAccessFile raf = new RandomAccessFile("camel.bin","rw");
            	//생성 직후 FilePointer의 위치는 0이다. 
                	System.out.printf("Currennt IO Position : %dByte", raf.getFilePointer());
            
            	raf.writeInt(100); // 4Byte의 데이터 삽입
            	raf.writeInt(200); // 4Byte의 데이터 삽입
            	System.out.printf("Currennt IO Position : %dByte", raf.getFilePointer());
            
            	raf.writeDouble(100.12); // 8Byte의 데이터 삽입
            	raf.writeDouble(200.43); // 8Byte의 데이터 삽입
            	System.out.printf("Currennt IO Position : %dByte", raf.getFilePointer());
            
            	System.out.println("---------------------------------");
            	
                	raf.seek(0); // FilePointer의 위치를 맨 앞으로 변경한다.
            	System.out.printf("Currennt IO Position : %dByte", raf.getFilePointer());
            
            	System.out.println(raf.readInt());
            	System.out.println(raf.readInt());
            	System.out.printf("Currennt IO Position : %dByte", raf.getFilePointer());
            
            	System.out.println(raf.readDouble());
            	System.out.println(raf.readDouble());
            	System.out.printf("Currennt IO Position : %dByte", raf.getFilePointer());
            
            	raf.close();
        	}
    }

     

     

     

    File 클래스

     여태까지 파일을 대상으로 하는 입출력에 대해 설명했습니다. 그런데 앞서 설명한 클래스를 사용해서 디렉터리를 생성하거나 소멸하는 것은 불가능합니다. 또한, 파일의 소멸과 디렉터리 내의 파일 이름을 출력하는 것 역시도 불가능합니다. 왜냐하면 이것들은 입출력에 관련된 것이 아니라 파일 및 디렉터리 관련 연산이기 때문입니다. 

     

     File 클래스는 이러한 파일 및 디렉터리 관련 일을 처리하기 위해 정의되어 있는 클래스입니다. File 클래스에 정의되어 있는 대표적인 메소드는 아래와 같습니다. 

     

    public boolean mkdir( ) - 디렉터리 생성을 위한 메소드. 

    public boolean mkdirs( ) - 디렉터리 생성을 위한 메소드. 

    public boolean renameTo( File dest ) - 파일의 이름을 변경하기 위한 메소드. 

     

    그런데 mkdir과 mkdirs의 차이는 무엇일까? mkdir 메소드를 사용해 디렉터리를 생성하고자 하는데 만약 주어진 디렉터리 위치정보가 존재하지 않는다면 오류가 발생하게됩니다. 존자하지 않는 디렉터리이기 때문에 생성도 할 수 없다는 것입니다. 

     하지만 mkdirs 메소드를 사용하면 오류가 발생하지 않고, 위치정보가 존재하지 않더라도 주어진 위치정보대로 디렉터리를 생성하게 됩니다. 

     

    mkdir & mkdirs 메소드 예제 코드

    class MakeDir {
    	public static void main ( String[] args ) {
        	File dir = new File("C:\\Java\\newDir");
            dir.mkdir();  // C:\\Java 디렉터리가 존재하지 않으면 오류 발생
        }
    }
    class MakeDirs {
    	public static void main ( String[] args ) {
        	File dir = new File("C:\\Java\\newDir");
            dir.mkdirs();  	// C:\\Java 디렉터리가 존재하지 않더라도 오류 발생하지 않음.
            		// C:\\Java 디렉터리 생성 후 newDir 디렉터리 생성
        }
    }

     

    renameTo 메소드 예제 코드

    renameTo 메소드는 파일의 이름을 변경하는 메소드라고 설명했지만 파일을 이동시키는 용도로 사용되기도 합니다. 

    class renameToFile {
    	public static void main ( String[] args ) {
        	// 두 파일 인스턴스는 파일의 위치정보를 가지고 있다. 
        	File oldFile = new File("C:\\Java\\oldDir\\camel.bin");
            File newFile = new File("C:\\Java\\newDir\\camel.bin");
            oldFile.renameTo(newFile);  	// 파일의 이름을 변경한 것이지만,  
            				// 이것은 파일의 이동으로 이어진다.
        }
    }

     

    Separator 메소드

     위의 예제 코드를 확인해보면 디렉터리의 표현 방식에서 구분자로 '\'를 사용하고 있습니다. 하지만 이것은 Windows 환경에서 쓰이는 구분자입니다. Linux의 경우는 '/'를 구분자로 사용하기 때문에 Linux 환경에서 위의 예제 코드를 실행시키면 제대로 동작하지 않습니다. 

     

     이런 문제를 해결하기 위해 사용하는 것이 separator 메소드입니다. separator 메소드를 활용해 운영체제에 상관없이 실행 가능한 코드로 변경하면 아래와 같습니다. 

    class renameToFile {
    	public static void main ( String[] args ) {
        	// 두 파일 인스턴스는 파일의 위치정보를 가지고 있다. 
        	File oldFile = new File("C:"+File.separator+"Java"+File.separator+"oldDir"+File.separator+"camel.bin");
            File newFile = new File("C:"+File.separator+"Java"+File.separator+"newDir"+File.separator+"camel.bin");
            oldFile.renameTo(newFile);  	// 파일의 이름을 변경한 것이지만,  
            				// 이것은 파일의 이동으로 이어진다.
        }
    }

     위와 같이 코드를 작성하면 실행환경에 따라서 적절하게 동작할 수 있을 것입니다. 하지만 여기서 한가지 더 생각해야하는 점은 C드라이브는 Windows에만 존재한다는 것입니다. 이런 문제는 절대경로의 한계라고 할 수 있습니다. 그렇기 때문에 우리는 절대경로가 아닌 상태경로를 기반으로 프로그램을 작성해야합니다. 

     

     상대경로란 현재의 디렉터리를 기준으로한 디렉터리 경로정보를 말합니다. 상대경로는 기준이 되는 디렉터리에 따라서 의미하는 바가 달라지게되고, 절대경로는 기준이 되는 디렉터리가 존재하지 않기 때문에 항상 일정한 디렉터리를 의미하게 됩니다. 

     

    상대경로를 활용한 코드 구성

    class RelativePath {
    	public static void main ( String[] args ) {
        	
        		File currentDir = new File("Java");
            	System.out.println(currentDir.getAbsolutePath());
            
            	File upperDir = new File("Java"+File.separator+"bin");
            	System.out.println(upperDir.getAbsolutePath());
            
        	}
    }

    위의 코드에서 사용된 getAbsolutePath 메소드는 File 인스턴스에 등록되어 있는 경로정보의 절대경로를 반환합니다. 

     

    추가적으로 대표적인 File 클래스의 인스턴스 메소드는 아래와 같습니다. 

    Type and Method Description ( 설명 )
    FIle[ ] listFIles( ) 디렉터리에 존재하는 파일과 디렉터리 정보를 반환
    String getName( ) 문자열의 형태로 파일 또는 디렉터리의 이름을 반환
    boolean isDirectory( ) 인스턴스의 정보가 디렉터리 정보인지 확인하기 위해 사용

    추가적으로 더 상세한 메소드 내역을 알고 싶으시면 아래 링크를 확인하시면 됩니다. 

    https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/io/File.html

    댓글

Camel`s Tistory.