[React-native] RnBlob cached Storage

Darcy Daeseok YU ·2026년 3월 18일
import RNFB from 'react-native-blob-util';
import { Platform } from 'react-native';

// IOS는 공용다운로드 dir이 없음.앱이 파일을 저장하면 해당 파일은 앱 전용 공간에 저장됩니다.
// ANDROID는 공용다운로드 dir이 있음.앱이 파일을 저장하면 해당 파일은 공용 다운로드 공간에 저장됩니다.
export const PLATFORM_DOWNLOAD_DIR = Platform.select({
  ios: RNFB.fs.dirs.DocumentDir, // 앱 내 캐쉬 저장소 ,공용다운로드 dir이 없음
  android: RNFB.fs.dirs.LegacyDownloadDir,
}) as string;

export const BASE_CACHE_DIR = Platform.select({
  ios: RNFB.fs.dirs.DocumentDir, // 앱 내 캐쉬 저장소
  android: RNFB.fs.dirs.DocumentDir, // react-native-file-viewer-turbo가 DocumentDir을 요구함
  //   android: RNFB.fs.dirs.CacheDir,  // CacheDir은 FileProvider와 호환성 문제 발생 가능
}) as string;

/**
 * 파일 저장 경로 정보를 반환합니다.
 * @returns 플랫폼별 저장 경로 정보
 */
export const getStoragePathInfo = () => {
  const documentDir = RNFB.fs.dirs.DocumentDir;
  const cacheDir = RNFB.fs.dirs.CacheDir;

  return {
    documentDir,
    cacheDir,
    currentStorageDir: BASE_CACHE_DIR,
    platform: Platform.OS,
    // 실제 경로 예시
    examplePath: Platform.select({
      ios: '/var/mobile/Containers/Data/Application/<App_UUID>/Documents',
      android: '/data/user/0/com.labotech.dentalsoft/files',
    }),
  };
};

export const isFileCached = async (fileName: string): Promise<boolean> => {
  const localFilePath = `${BASE_CACHE_DIR}/${fileName}`;
  return await RNFB.fs.exists(localFilePath);
};

/**
 * [선택 사항] 특정 캐시 파일을 디스크에서 삭제합니다.
 * @param fileName 삭제할 파일 이름
 */
export const deleteCachedFile = async (fileName: string): Promise<boolean> => {
  const localFilePath = `${BASE_CACHE_DIR}/${fileName}`;
  try {
    await RNFB.fs.unlink(localFilePath);
    console.log(`[DiskCache] 파일 삭제 완료: ${fileName}`);
    return true;
  } catch (error) {
    console.error(`[DiskCache] 파일 삭제 실패: ${error}`);
    return false;
  }
};

/**
 * 캐시 디렉토리의 모든 파일을 삭제합니다.
 * @returns 삭제된 파일 개수
 */
export const clearCache = async (): Promise<number> => {
  try {
    // 디렉토리 내 모든 파일 목록 가져오기
    const files = await RNFB.fs.lstat(BASE_CACHE_DIR);

    if (files.length === 0) {
      console.log('[DiskCache] 삭제할 파일이 없습니다.');
      return 0;
    }

    // 각 파일 삭제
    let deletedCount = 0;
    for (const file of files) {
      try {
        const filePath = file.path;
        // lstat는 이미 파일 정보를 포함하므로 별도 stat 호출 불필요
        if (file.type === 'file' || file.type === 'directory') {
          await RNFB.fs.unlink(filePath);
          deletedCount++;
        }
      } catch (error) {
        console.error(
          `[DiskCache] 파일 삭제 실패: ${file.filename || file.path}`,
          error
        );
      }
    }

    console.log(`[DiskCache] 캐시 클리어 완료: ${deletedCount}개 파일 삭제`);
    return deletedCount;
  } catch (error) {
    console.error('[DiskCache] 캐시 클리어 실패:', error);
    throw error;
  }
};

/**
 * 캐시 디렉토리의 사용량을 확인합니다.
 * @returns 파일 개수와 총 크기 (bytes)
 */
export const getCacheInfo = async (): Promise<{
  fileCount: number;
  totalSize: number;
}> => {
  try {
    const files = await RNFB.fs.lstat(BASE_CACHE_DIR);
    let totalSize = 0;
    let fileCount = 0;

    for (const file of files) {
      try {
        // lstat는 이미 파일 정보를 포함하므로 별도 stat 호출 불필요
        if (file.type === 'file') {
          totalSize += file.size || 0;
          fileCount++;
        }
      } catch (error) {
        // 파일 정보를 가져올 수 없는 경우 무시
        console.warn(
          `[DiskCache] 파일 정보 가져오기 실패: ${file.filename || file.path}`
        );
      }
    }

    return { fileCount, totalSize };
  } catch (error) {
    console.error('[DiskCache] 캐시 정보 가져오기 실패:', error);
    return { fileCount: 0, totalSize: 0 };
  }
};
입력하세요
profile
React, React-Native https://darcyu83.netlify.app/

0개의 댓글