Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tomevault-io/skills-registry --skill maui-file-handling명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | maui-file-handling |
| description | > Use when this capability is needed. |
OpenReadAsync(), Not FullPathSome platforms (especially Android) return content URIs, not file system
paths. Reading FullPath directly will throw or return empty data.
// ❌ Breaks on Android — FullPath may be a content:// URI
var result = await FilePicker.Default.PickAsync();
var bytes = File.ReadAllBytes(result.FullPath);
// ✅ Works on all platforms
var result = await FilePicker.Default.PickAsync();
if (result is not null)
{
using var stream = await result.OpenReadAsync();
// process stream
}
Each platform uses a different format for custom FilePickerFileType.
Mixing them up causes the picker to show no files or crash.
| Platform | Format | Example |
|---|---|---|
| Android | MIME types | "application/json" |
| iOS / macOS | UTType identifiers | "public.json" |
| Windows | Dot-prefixed extensions | ".json" |
// ❌ Using file extensions for Android — picker shows nothing
{ DevicePlatform.Android, new[] { ".json", ".txt" } }
// ✅ Correct MIME types for Android
{ DevicePlatform.Android, new[] { "application/json", "text/plain" } }
Resources/Raw assets cannot be modified at runtime. Attempting to write
throws an exception (or silently fails on some platforms).
// ❌ Trying to write to a bundled file
var path = "data.json"; // inside Resources/Raw
File.WriteAllText(path, newContent); // fails
// ✅ Copy to AppDataDirectory first, then modify
string targetPath = Path.Combine(FileSystem.Current.AppDataDirectory, "data.json");
if (!File.Exists(targetPath))
{
using var source = await FileSystem.Current.OpenAppPackageFileAsync("data.json");
using var dest = File.Create(targetPath);
await source.CopyToAsync(dest);
}
// Now safe to read/write targetPath
On some platforms, Resources/Raw/subdir/file.txt becomes just file.txt.
Use unique file names regardless of subdirectory structure.
The iOS sandbox path includes an app GUID that changes across clean builds. Hard-coded absolute paths break silently.
// ❌ Hard-coded path — breaks after clean rebuild
var path = "/var/mobile/.../Documents/data.json";
// ✅ Always use the FileSystem helper
var path = Path.Combine(FileSystem.Current.AppDataDirectory, "data.json");
LengthOpenAppPackageFileAsync may return a stream where .Length throws
NotSupportedException. Copy to a MemoryStream if you need the size.
// ❌ Throws on Android
using var stream = await FileSystem.Current.OpenAppPackageFileAsync("data.json");
var size = stream.Length; // NotSupportedException
// ✅ Copy first if you need the length
using var stream = await FileSystem.Current.OpenAppPackageFileAsync("data.json");
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var size = ms.Length;
Packaged apps silently redirect writes to classic paths like %AppData%.
Always use AppDataDirectory and CacheDirectory for reliable
cross-platform paths.
null on cancellation// ❌ NullReferenceException when user cancels
var result = await FilePicker.Default.PickAsync();
using var stream = await result.OpenReadAsync();
// ✅ Always null-check
var result = await FilePicker.Default.PickAsync();
if (result is null) return;
using var stream = await result.OpenReadAsync();
Android 13 replaced READ_EXTERNAL_STORAGE with granular media permissions.
Using the old permission on API 33+ silently grants nothing.
| Android version | Required permission |
|---|---|
| ≤ 12 (API 32) | READ_EXTERNAL_STORAGE |
| ≥ 13 (API 33) | READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO |
OpenReadAsync() — never read FullPath directlyFilePicker result before accessing propertiesFilePickerFileType uses correct format per platform (MIME / UTType / extension)AppDataDirectory before modificationResources/Raw (subdirectories are flattened)Converted and distributed by TomeVault — claim your Tome and manage your conversions.