태그 보관물: FIle

Android에서 content:/// 스키마의 Uri를 file:/// 스키마의 Uri로 변경하기..

안드로이드에서, 앱으로 파일을 공유하는 경우, 위치를 받아오는 포맷이 크게 2가지가 있다. 

하나는 content:/// 스키마의 포맷이고, 다른 하나는 file:/// 스키마의 포맷으로 Uri 객체나 리스트 Uri를 받을 수 있다. 그리고, 파일을 공유받기 위해서는 ACTION_SEND와 ACTION_SEND_MULTIPLE를 AndroidManifest.xml 파일에서 해당 Action을 처리하는 Activity안에 기술해 준다. 


	
    
	
        
        
        
        
        
        
        
    
    
        
        
       	
        
        
        
        
        
    

위의 과정을 통해서, 서비스하는 앱이 다른 앱에서 공유하는 파일의 위치를 받아서 업로드를 하거나, 파일을 전송할 수 있다. 위의 content:/// 스키마를 사용하는 기본 갤러리 앱등에서 받은 content:/// Uri를 file:/// 스키마의 Uri로 변경시켜 주는 코드이다. 

	/**
	 * Uri 스키마를 content:/// 에서 file:/// 로  변경한다.
	 * 
	 * @param ctx
	 * @param uri
	 * @return
	 * @throws Exception
	 */
	public static Uri convertContentToFileUri(Context ctx, Uri uri) throws Exception {
		Cursor cursor = null;
		try {
			cursor = ctx.getContentResolver().query(uri, null, null, null, null);
			cursor.moveToNext();
			return Uri.fromFile(new File(cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA))));
		} finally {
			if(cursor != null)
				cursor.close();
		}
	}	

자, 이제 변경된 Uri에서 파일의 위치를 가져와서 I/O 작업을 할 수 있겠다..

Java에서 파일 이름의 유효성 체크 및 이름 바꾸기..

기본적으로 OS에서는 특수 캐릭터가 예약되어 있어, 파일 이름으로 사용할 수 없다.

그래서, 프로그램에서 파일 관련 작업을 하기 전에, 파일 이름에 대한 유효성 체크와 파일 이름에 대한 변환이 필요한 경우가 있다. 위에 대한 내용은, http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words나 http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx#naming_conventions에서 OS별로 예약되어 있는 캐릭터와 파일의 길이를 확인할 수 있다.

아래는 위의 MSDN 링크(윈도우 OS)에 나와 있는 대표적인 캐릭터이고, 추가적인 문자열은 위 링크에서 확인할 수 있다.

< (less than)
> (greater than)
: (colon)
” (double quote)
/ (forward slash)
\ (backslash)
| (vertical bar or pipe)
? (question mark)
* (asterisk)

아래는 자바로 위의 제약조건에 대한 확인을 제공하는 클래스이다.

import java.util.regex.Pattern;
public class FileNameUtil {
	// 파일이름 확인..
	static final String ILLEGAL_EXP = "[:\\\\/%*?:|\"<>]";

	/**
	 * 파일 이름이 유효한지 확인한다.
	 * 
	 * @author mcsong@gmail.com
	 * @param fileName 파일의 이름, Path를 제외한 순수한 파일의 이름.. 
	 * @return
	 */
	public static boolean isValidFileName(String fileName) {
	    if(fileName == null || fileName.trim().length() == 0)
	    	return false;

		return !Pattern.compile(ILLEGAL_EXP).matcher(fileName).find();
	}

	/**
	 * 파일 이름에 사용할 수 없는 캐릭터를 바꿔서 유효한 파일로 만든다.
	 * 
	 * @author mcsong@gmail.com
	 * @param fileName 파일 이름, Path를 제외한 순수한 파일의 이름..
	 * @param replaceStr 파일 이름에 사용할 수 없는 캐릭터의 교체 문자
	 * @return
	 */
	public static String makeValidFileName(String fileName, String replaceStr) {
	    if(fileName == null || fileName.trim().length() == 0 || replaceStr == null)
	    	return String.valueOf(System.currentTimeMillis());		

	    return fileName.replaceAll(ILLEGAL_EXP, replaceStr);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

	    String c = "!\"#$%&(){}@`*:+;-.<>,^~|'[]akdfsjhex.txt"; 

	    System.out.println("bbbb --> " + isValidFileName("abcde.jpg"));
	    System.out.println("bbbb --> " + isValidFileName(c));
	    System.out.println("bbbb --> " + makeValidFileName(c, "_") );        
	}
}

위 코드는 자바 환경인 안드로이드에서도 사용할 수 있다.

BufferedWriter vs BufferedOutputStream 성능차이..

로그 데이터를 파일에 저장하기 위해서 BufferedWriter 클래스를 사용하다가, 갑자기 BufferedOutputStream으로 처리하는 것과의 성능상 차이에 대해서 확인하고 싶어서, 동일한 데이타를 파일에 저장해 봤다. 두 클래스의 성능 차이는 별로 없어 보이지만 그래도 확인 해 보자. 아래의 BufferWriterTest, BufferOutputStream 클래스의 buffersize는 1024로 동일하다.

– BufferWriterTest.java

import java.util.*;
import java.text.*;
import java.io.*;

public class BufferWriterTest {
	//
	static DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");

	static String txt = "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하" + "가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하마바사아자차타파하";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Date start = new Date();
		System.out.println("s – " + df.format(start));

		BufferedWriter bufferWriter;

		try {
			bufferWriter = new BufferedWriter(new FileWriter("c:\\BufferedWriter.txt", true), 1024);
			for (int i = 0; i < 5000000; i++) {
				bufferWriter.write(BufferWriterTest.txt);
				bufferWriter.newLine();
			}

			bufferWriter.flush();
			bufferWriter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		Date end = new Date();
		System.out.println("e – " + df.format(end));
	}
}

결과(3.15G 파일 쓰기)

s – 2009-06-19 15:55:00:968
e – 2009-06-19 15:55:48:280

– BufferOutputStreamTest.java

import java.io.IOException;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class BufferOutputStreamTest {
	//
	static DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
	static String txt = "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ 	"가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라"
			+	"가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ 	"가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+	"가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하" 
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하"
			+ "가나다라마바사아자차타파하가나다라마바사아자차타파하가나다라마바사아자차타파하" 
			+ 	"가나다라마바사아자차타파하마바사아자차타파하";

	/**
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Date start = new Date();
		System.out.println("s – " + df.format(start));

		BufferedOutputStream bufferedOutput;
		try {
			bufferedOutput = new BufferedOutputStream(new FileOutputStream("c:\\BufferedStream.txt", true), 1024);

			for (int i = 0; i < 5000000; i++) {
				bufferedOutput.write(txt.getBytes());
				bufferedOutput.write("\n".getBytes());
			}
			bufferedOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		Date end = new Date();
		System.out.println("e – " + df.format(end));
	}
}

결과(3.15G 파일 쓰기, )

s – 2009-06-19 15:56:41:889
e – 2009-06-19 15:58:19:825

위 결과를 보면, 비슷한 사이즈의 파일을 추가할 경우에 꽤 성능차이가 난다. 느낌에는 비슷한 성능을 낼 것으로 생각이 드는데, 스트링 처리는 Reader/Writer 시리즈가 더 적합하다는 것인가? 혹시 아래의 구조 때문에 그럴까요? 아시는 분은 조언을..

BufferedWriter BufferedOutputStream
java.lang.Object
– java.io.Writer
– java.io.BufferedWriter
java.lang.Object
– java.io.OutputStream
– java.io.FilterOutputStream
– java.io.BufferedOutputStream

파일에 락 걸기..

try {
        File file = new File(“filename”);
        FileChannel channel = new RandomAccessFile(file, “rw”).getChannel();

        FileLock lock = channel.lock();
        try {
            lock = channel.tryLock();
        } catch (OverlappingFileLockException e) {
            // File is already locked in this thread or virtual machine
        }

        lock.release();

        channel.close();
        
}catch(Exception e){
}