ফাইল এবং ডিরেক্টরি পড়া এবং লেখা

প্রকাশিত: ২৭ জুলাই, ২০২০

ব্রাউজারগুলি দীর্ঘদিন ধরে ফাইল এবং ডিরেক্টরিগুলি পরিচালনা করতে সক্ষম হয়েছে। ফাইল API ওয়েব অ্যাপ্লিকেশনগুলিতে ফাইল অবজেক্টগুলি উপস্থাপন করার পাশাপাশি প্রোগ্রাম্যাটিকভাবে সেগুলি নির্বাচন এবং তাদের ডেটা অ্যাক্সেস করার জন্য বৈশিষ্ট্য সরবরাহ করে। তবে আপনি যখনই ঘনিষ্ঠভাবে তাকান, তখনই দেখা যাবে যে সমস্ত চকচকে জিনিস সোনার নয়।

ফাইল পরিচালনার ঐতিহ্যবাহী পদ্ধতি

ফাইল খুলুন

<input type="file"> এলিমেন্ট দিয়ে আপনি ফাইল খুলতে এবং পড়তে পারেন। সহজতম আকারে, একটি ফাইল খোলা কোড নমুনার মতো দেখতে হতে পারে। input অবজেক্ট আপনাকে একটি FileList দেয়, যা আমাদের উদাহরণের ক্ষেত্রে, শুধুমাত্র একটি File নিয়ে গঠিত। একটি File হল একটি নির্দিষ্ট ধরণের Blob , এবং এটি একটি Blob যে কোনও প্রসঙ্গে ব্যবহার করা যেতে পারে।

const openFile = async () => {
  return new Promise((resolve) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.addEventListener('change', () => {
      resolve(input.files[0]);
    });
    input.click();
  });
};

ডিরেক্টরি খোলা হচ্ছে

ফোল্ডার (অথবা ডিরেক্টরি) খোলার জন্য, আপনি <input webkitdirectory> অ্যাট্রিবিউট সেট করতে পারেন। তা ছাড়া, বাকি সবকিছু উপরের মতোই কাজ করে। এর বিক্রেতা-প্রিফিক্সড নাম থাকা সত্ত্বেও, webkitdirectory শুধুমাত্র Chromium এবং WebKit ব্রাউজারেই নয়, বরং লিগ্যাসি EdgeHTML-ভিত্তিক Edge এবং Firefox-এও ব্যবহারযোগ্য।

ফাইলগুলি সংরক্ষণ এবং ডাউনলোড করুন

একটি ফাইল সংরক্ষণের জন্য, ঐতিহ্যগতভাবে, আপনি একটি ফাইল ডাউনলোড করতে সীমাবদ্ধ থাকেন, যা <a download> অ্যাট্রিবিউটের জন্য কাজ করে। একটি Blob দেওয়া হলে, আপনি অ্যাঙ্করের href অ্যাট্রিবিউটটিকে একটি blob: URL এ সেট করতে পারেন যা আপনি URL.createObjectURL() পদ্ধতি থেকে পেতে পারেন।

const saveFile = async (blob) => {
  const a = document.createElement('a');
  a.download = 'my-file.txt';
  a.href = URL.createObjectURL(blob);
  a.addEventListener('click', (e) => {
    setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
  });
  a.click();
};

সমস্যাটি

ডাউনলোড পদ্ধতির একটি বড় অসুবিধা হল, ক্লাসিক ওপেন→এডিট→সেভ ফ্লো ঘটানোর কোনও উপায় নেই, অর্থাৎ, মূল ফাইলটি ওভাররাইট করার কোনও উপায় নেই। পরিবর্তে, আপনি যখনই "সেভ" করবেন তখন অপারেটিং সিস্টেমের ডিফল্ট ডাউনলোড ফোল্ডারে মূল ফাইলের একটি নতুন কপি পাবেন।

ফাইল সিস্টেম অ্যাক্সেস API

ফাইল সিস্টেম অ্যাক্সেস API খোলা এবং সংরক্ষণ উভয় কাজই অনেক সহজ করে তোলে। এটি সত্য সংরক্ষণও সক্ষম করে। এর অর্থ হল আপনি ফাইলটি কোথায় সংরক্ষণ করবেন এবং বিদ্যমান ফাইলটি ওভাররাইট করবেন তা বেছে নিতে পারেন।

ফাইল খুলুন

With the File System Access API , opening a file is a matter of one call to the window.showOpenFilePicker() method. This call returns a file handle, from which you can get the actual File via the getFile() method.

const openFile = async () => {
  try {
    // Always returns an array.
    const [handle] = await window.showOpenFilePicker();
    return handle.getFile();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

ডিরেক্টরি খুলুন

window.showDirectoryPicker() কল করে একটি ডিরেক্টরি খুলুন যা ফাইল ডায়ালগ বক্সে ডিরেক্টরিগুলি নির্বাচনযোগ্য করে তোলে।

ফাইল সংরক্ষণ করুন

ফাইল সংরক্ষণ করাও একইভাবে সহজ। একটি ফাইল হ্যান্ডেল থেকে, আপনি createWritable() এর মাধ্যমে একটি লেখার যোগ্য স্ট্রিম তৈরি করেন, তারপর আপনি স্ট্রিমের write() পদ্ধতিটি কল করে ব্লব ডেটা লেখেন এবং অবশেষে আপনি এর close() পদ্ধতিটি কল করে স্ট্রিমটি বন্ধ করেন।

const saveFile = async (blob) => {
  try {
    const handle = await window.showSaveFilePicker({
      types: [{
        accept: {
          // Omitted
        },
      }],
    });
    const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
    return handle;
  } catch (err) {
    console.error(err.name, err.message);
  }
};

ব্রাউজার-এফএস-অ্যাক্সেস চালু করা হচ্ছে

ফাইল সিস্টেম অ্যাক্সেস এপিআই যতই নিখুঁত হোক না কেন, এটি এখনও ব্যাপকভাবে উপলব্ধ নয়

ফাইল সিস্টেম অ্যাক্সেস API-এর জন্য ব্রাউজার সাপোর্ট টেবিল। সমস্ত ব্রাউজার 'কোনও সাপোর্ট নেই' অথবা 'একটি পতাকার পিছনে' হিসাবে চিহ্নিত করা হয়েছে।
ফাইল সিস্টেম অ্যাক্সেস API-এর জন্য ব্রাউজার সাপোর্ট টেবিল। ( সূত্র )

এই কারণেই আমি ফাইল সিস্টেম অ্যাক্সেস API-কে একটি প্রগতিশীল বর্ধন হিসেবে দেখি। তাই, আমি ব্রাউজার যখন এটি সমর্থন করে তখন এটি ব্যবহার করতে চাই, এবং যদি না থাকে তবে ঐতিহ্যবাহী পদ্ধতি ব্যবহার করতে চাই; এবং ব্যবহারকারীকে অসমর্থিত জাভাস্ক্রিপ্ট কোডের অপ্রয়োজনীয় ডাউনলোড দিয়ে কখনও শাস্তি দেব না। browser-fs-access লাইব্রেরি হল এই চ্যালেঞ্জের আমার উত্তর।

নকশা দর্শন

যেহেতু ভবিষ্যতে ফাইল সিস্টেম অ্যাক্সেস API-তে এখনও পরিবর্তন হওয়ার সম্ভাবনা রয়েছে, তাই browser-fs-access API-কে এর অনুকরণে তৈরি করা হয়নি। অর্থাৎ, লাইব্রেরিটি কোনও পলিফিল নয়, বরং একটি পনিফিল । আপনার অ্যাপটিকে যতটা সম্ভব ছোট রাখার জন্য আপনি (স্ট্যাটিক্যালি বা ডাইনামিকলি) একচেটিয়াভাবে যে কোনও কার্যকারিতা আমদানি করতে পারেন। উপলব্ধ পদ্ধতিগুলি হল উপযুক্তভাবে নামকরণ করা হয়েছে fileOpen() , directoryOpen() , এবং fileSave() । অভ্যন্তরীণভাবে, লাইব্রেরি বৈশিষ্ট্যটি সনাক্ত করে যে ফাইল সিস্টেম অ্যাক্সেস API সমর্থিত কিনা এবং তারপরে সংশ্লিষ্ট কোড পাথ আমদানি করে।

লাইব্রেরি ব্যবহার করুন

তিনটি পদ্ধতি ব্যবহার করা খুবই সহজ। আপনি আপনার অ্যাপের গৃহীত mimeTypes বা ফাইল extensions নির্দিষ্ট করতে পারেন এবং একাধিক ফাইল বা ডিরেক্টরি নির্বাচনের অনুমতি বা বাতিল করার জন্য multiple ফ্ল্যাগ সেট করতে পারেন। সম্পূর্ণ বিবরণের জন্য, browser-fs-access API ডকুমেন্টেশন দেখুন। কোড নমুনাটি দেখায় যে আপনি কীভাবে চিত্র ফাইল খুলতে এবং সংরক্ষণ করতে পারেন।

// The imported methods will use the File
// System Access API or a fallback implementation.
import {
  fileOpen,
  directoryOpen,
  fileSave,
} from 'https://unpkg.com/browser-fs-access';

(async () => {
  // Open an image file.
  const blob = await fileOpen({
    mimeTypes: ['image/*'],
  });

  // Open multiple image files.
  const blobs = await fileOpen({
    mimeTypes: ['image/*'],
    multiple: true,
  });

  // Open all files in a directory,
  // recursively including subdirectories.
  const blobsInDirectory = await directoryOpen({
    recursive: true
  });

  // Save a file.
  await fileSave(blob, {
    fileName: 'Untitled.png',
  });
})();

ডেমো

আপনি GitHub-এর একটি ডেমোতে কোডটি কার্যকর দেখতে পাবেন। এর সোর্স কোডও সেখানে পাওয়া যাবে।

ব্রাউজার-এফএস-অ্যাক্সেস লাইব্রেরি বর্তমানে বিদ্যমান

আমার অবসর সময়ে, আমি Excalidraw নামক একটি ইনস্টলযোগ্য PWA- তে সামান্য অবদান রাখি, এটি একটি হোয়াইটবোর্ড টুল যা আপনাকে হাতে আঁকা অনুভূতি দিয়ে ডায়াগ্রাম স্কেচ করতে দেয়। এটি সম্পূর্ণরূপে প্রতিক্রিয়াশীল এবং ছোট মোবাইল ফোন থেকে শুরু করে বড় স্ক্রিনযুক্ত কম্পিউটার পর্যন্ত বিভিন্ন ডিভাইসে ভালভাবে কাজ করে। এর অর্থ হল এটি ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করুক বা না করুক, সমস্ত প্ল্যাটফর্মের ফাইলগুলি মোকাবেলা করতে হবে। এটি এটিকে browser-fs-access লাইব্রেরির জন্য একটি দুর্দান্ত প্রার্থী করে তোলে।

I can, for example, start a drawing on my iPhone, save it (technically: download it, since Safari does not support the File System Access API) to my iPhone Downloads folder, open the file on my desktop (after transferring it from my phone), modify the file, and overwrite it with my changes, or even save it as a new file.

আইফোনে একটি এক্সক্যালিড্র অঙ্কন।
এমন একটি আইফোনে এক্সক্যালিড্রাউ অঙ্কন শুরু করা যেখানে ফাইল সিস্টেম অ্যাক্সেস API সমর্থিত নয়, কিন্তু যেখানে একটি ফাইল ডাউনলোড ফোল্ডারে সংরক্ষণ (ডাউনলোড) করা যেতে পারে।
ডেস্কটপে Chrome-এ পরিবর্তিত Excalidraw অঙ্কন।
ডেস্কটপে এক্সক্যালিড্রাউ অঙ্কন খোলা এবং সংশোধন করা যেখানে ফাইল সিস্টেম অ্যাক্সেস API সমর্থিত এবং এইভাবে API এর মাধ্যমে ফাইলটি অ্যাক্সেস করা যেতে পারে।
পরিবর্তনগুলি সহ মূল ফাইলটি ওভাররাইট করা হচ্ছে।
মূল ফাইলটি মূল এক্সক্যালিড্রাউ ড্রয়িং ফাইলের পরিবর্তনের সাথে ওভাররাইট করছে। ব্রাউজারটি একটি ডায়ালগ দেখায় যেখানে আমাকে জিজ্ঞাসা করা হচ্ছে যে এটি ঠিক আছে কিনা।
পরিবর্তনগুলি একটি নতুন এক্সক্যালিড্রাও অঙ্কন ফাইলে সংরক্ষণ করা হচ্ছে।
পরিবর্তনগুলি একটি নতুন এক্সক্যালিড্রা ফাইলে সংরক্ষণ করা হচ্ছে। মূল ফাইলটি অক্ষত রয়ে গেছে।

বাস্তব জীবনের কোডের নমুনা

নিচে, আপনি Excalidraw-এ ব্যবহৃত browser-fs-access-এর একটি বাস্তব উদাহরণ দেখতে পাবেন। এই অংশটি /src/data/json.ts থেকে নেওয়া হয়েছে। বিশেষ আগ্রহের বিষয় হল saveAsJSON() পদ্ধতি কীভাবে একটি ফাইল হ্যান্ডেল বা null ব্রাউজার-fs-access' fileSave() পদ্ধতিতে প্রেরণ করে, যার ফলে একটি হ্যান্ডেল দেওয়া হলে এটি ওভাররাইট করে, অথবা যদি না দেওয়া হয় তাহলে একটি নতুন ফাইলে সংরক্ষণ করে।

export const saveAsJSON = async (
  elements: readonly ExcalidrawElement[],
  appState: AppState,
  fileHandle: any,
) => {
  const serialized = serializeAsJSON(elements, appState);
  const blob = new Blob([serialized], {
    type: "application/json",
  });
  const name = `${appState.name}.excalidraw`;
  (window as any).handle = await fileSave(
    blob,
    {
      fileName: name,
      description: "Excalidraw file",
      extensions: ["excalidraw"],
    },
    fileHandle || null,
  );
};

export const loadFromJSON = async () => {
  const blob = await fileOpen({
    description: "Excalidraw files",
    extensions: ["json", "excalidraw"],
    mimeTypes: ["application/json"],
  });
  return loadFromBlob(blob);
};

UI বিবেচ্য বিষয়গুলি

এক্সক্যালিড্রাও হোক বা আপনার অ্যাপ, UI ব্রাউজারের সাপোর্ট পরিস্থিতির সাথে খাপ খাইয়ে নেওয়া উচিত। যদি ফাইল সিস্টেম অ্যাক্সেস API সমর্থিত হয় ( if ('showOpenFilePicker' in window) {} ) তাহলে আপনি একটি সেভ বোতামের পাশাপাশি একটি সেভ অ্যাজ বোতামও দেখাতে পারেন। নীচের স্ক্রিনশটগুলি আইফোন এবং ক্রোম ডেস্কটপে এক্সক্যালিড্রার প্রতিক্রিয়াশীল প্রধান অ্যাপ টুলবারের মধ্যে পার্থক্য দেখায়। লক্ষ্য করুন কিভাবে আইফোনে সেভ অ্যাজ বোতামটি অনুপস্থিত।

আইফোনে এক্সক্যালিড্রাও অ্যাপ টুলবার শুধুমাত্র একটি 'সংরক্ষণ' বোতাম দিয়ে।
আইফোনে এক্সক্যালিড্রা অ্যাপ টুলবার শুধুমাত্র একটি সেভ বোতাম দিয়ে।
Chrome-এ Excalidraw অ্যাপ টুলবার, যেখানে একটি Save এবং একটি ফোকাসড Save As বোতাম থাকবে।

উপসংহার

সিস্টেম ফাইল নিয়ে কাজ করা প্রযুক্তিগতভাবে সকল আধুনিক ব্রাউজারেই কাজ করে। যেসব ব্রাউজার ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করে, সেখানে আপনি ফাইলগুলিকে সত্যিকার অর্থে সংরক্ষণ এবং ওভাররাইট করার (শুধু ডাউনলোড নয়) অনুমতি দিয়ে এবং আপনার ব্যবহারকারীদের যেখানে খুশি নতুন ফাইল তৈরি করতে দিয়ে অভিজ্ঞতা আরও উন্নত করতে পারেন, একই সাথে ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করে না এমন ব্রাউজারগুলিতে কার্যকরী থাকা। ব্রাউজার-এফএস-অ্যাক্সেস প্রগতিশীল বর্ধনের সূক্ষ্মতাগুলি মোকাবেলা করে এবং আপনার কোডকে যতটা সম্ভব সহজ করে আপনার জীবনকে সহজ করে তোলে।

স্বীকৃতি

এটি পর্যালোচনা করেছেন জো মেডলি এবং কেইস বাস্কেস । প্রকল্পে কাজ করার জন্য এবং আমার পুল রিকোয়েস্ট পর্যালোচনা করার জন্য এক্সক্যালিড্র-এর অবদানকারীদের ধন্যবাদ।