דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. מעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה

מעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה

מתוזמן נעוץ נעול הועבר תכנות
18 פוסטים 6 כותבים 139 צפיות 5 עוקבים
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
תגובה
  • תגובה כנושא
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • E מנותק
    E מנותק
    eido
    כתב נערך לאחרונה על ידי
    #1

    מה הדרך הטובה ביותר לעבור על תיקיות ותתי תיקיות על כל קבציהן מבלי להשתמש ברקורסיה? צריך שיהיה אפשר בקלות לעצור בנקודה מסוימת ולהמשיך ממנה אח"כ.
    לתפוס מינימום זכרון בו זמנית.

    תגובה 1 תגובה אחרונה
    0
    • dovidD מנותק
      dovidD מנותק
      dovid
      ניהול
      כתב נערך לאחרונה על ידי
      #2

      אתה עדיין חושב שהבעיה היא רקורסיה.
      אתה לא עובר על תיקיות אלא על בקשות אינטרנט.
      הרקורסיה זה סה"כ מבנה להשיג את כל הנתיבים.
      מה שלוקח לך את הזמן זה בקשת האינטרנט, זה לא משנה אם זה יהיה בלולאה או בפטיש ומסמר.
      אתה צריך פשוט להתקדם צעד צעד, לשמור מצב, ולהתקדם.
      נכון, זה לא פשוט, ואתה בטח תגיד שזה לא צודק/מובן וניסית ולא עבד.

      • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
      • בכל נושא אפשר ליצור קשר dovid@tchumim.com
      E 2 תגובות תגובה אחרונה
      0
      • dovidD dovid

        אתה עדיין חושב שהבעיה היא רקורסיה.
        אתה לא עובר על תיקיות אלא על בקשות אינטרנט.
        הרקורסיה זה סה"כ מבנה להשיג את כל הנתיבים.
        מה שלוקח לך את הזמן זה בקשת האינטרנט, זה לא משנה אם זה יהיה בלולאה או בפטיש ומסמר.
        אתה צריך פשוט להתקדם צעד צעד, לשמור מצב, ולהתקדם.
        נכון, זה לא פשוט, ואתה בטח תגיד שזה לא צודק/מובן וניסית ולא עבד.

        E מנותק
        E מנותק
        eido
        כתב נערך לאחרונה על ידי
        #3

        @dovid אני לא חושב שהבעיה היא רקורסיה, אני בסה"כ מחפש דרך אחרת...
        האמת שקשה לי לדמיין איך לעשות את זה עם רקורסיה, לבקש שיכתבו לי קוד - אני לא רוצה, אין לי זמן להשקיע בבנית אלגוריתם שגם ימדוד זמן, גם יבדוק שהמשאבים שהוא דורש לא חוצים את הרף של גוגל סקריפט (לא כ"כ נדיבים לפי מה שהבנתי, אולי אני טועה) וגם יתן לי לחזור לאותו מקום שבו הוא עצר תוך כדי שמירת מבנה הגיבוי (פשוט אותו מבנה שבו הוא נמצא שם - בשרת של ימות המשיח).

        למה לא פשוט למצוא דרך אחרת שיותר תתאים לי, בתור מתכנת מתחיל וחסר ידע וזמן?

        גם המבנה הסופי של הגיבוי הוא בצורה מסוימת מסיבה מסוימת, ורקורסיה עם תחנות עצירה מאוד מקשים על זה, לפחות עד כמה שאני יודע.

        לכן שאלתי שאלה פשוטה, בלי הנחות מקדימות ובלי שום דבר פשוט בקשת מידע, מה הדרך הנכונה.

        תגובה 1 תגובה אחרונה
        0
        • dovidD dovid

          אתה עדיין חושב שהבעיה היא רקורסיה.
          אתה לא עובר על תיקיות אלא על בקשות אינטרנט.
          הרקורסיה זה סה"כ מבנה להשיג את כל הנתיבים.
          מה שלוקח לך את הזמן זה בקשת האינטרנט, זה לא משנה אם זה יהיה בלולאה או בפטיש ומסמר.
          אתה צריך פשוט להתקדם צעד צעד, לשמור מצב, ולהתקדם.
          נכון, זה לא פשוט, ואתה בטח תגיד שזה לא צודק/מובן וניסית ולא עבד.

          E מנותק
          E מנותק
          eido
          כתב נערך לאחרונה על ידי
          #4

          @dovid כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

          אתה עדיין חושב שהבעיה היא רקורסיה.
          אתה לא עובר על תיקיות אלא על בקשות אינטרנט.
          הרקורסיה זה סה"כ מבנה להשיג את כל הנתיבים.
          מה שלוקח לך את הזמן זה בקשת האינטרנט, זה לא משנה אם זה יהיה בלולאה או בפטיש ומסמר.
          אתה צריך פשוט להתקדם צעד צעד, לשמור מצב, ולהתקדם.
          נכון, זה לא פשוט, ואתה בטח תגיד שזה לא צודק/מובן וניסית ולא עבד.

          אם לדוגמא אשלח בקשה, אפתח תיקיה בדרייב בעלת אותו השם ואשמור את כל הנתיבים כך - נתיב בשרת, ID התיקיה.
          אסיים את התיקיה הנ"ל ואתחיל תת תיקיה וכו'
          ככה מסיימים תיקיה ועוברים הלאה, מציאת הנתיבים של כל הקבצים זה הרבה יותר מהיר מאשר הורדה שלהם, והרבה יותר קל להתחיל מחדש. ולאחר שיש לי רשימה מסודרת של נתיבים ואיפה הם אמורים להיות גם יותר קל להוריד אותם לאט לאט, אפשר אפילו להפעיל טריגרים בהפרדה של כמה שניות וככה לעשות את כל התהליך הרבה יותר מהר.

          אתה לא מסכים איתי? מי אמר שכאן רקורסיה + תחנות עצירה הם דוקא הפתרון הנכון?

          תגובה 1 תגובה אחרונה
          0
          • יהודי טובי מנותק
            יהודי טובי מנותק
            יהודי טוב
            כתב נערך לאחרונה על ידי
            #5

            @eido

            אם מעניין אותך יש לי את הקוד הזה בnode.
            שאני דבר ראשון מקבל את כל הנתיבים של הקבצים - שזה בקשות לא כבדות.
            ואח"כ אני עובר על כל הקבצים עם מידע כמה אחוז כבר ירד (ושומר לקובץ ZIP את מה שנוצר)

            
            
            // ============================================
            // ייבוא מודולים
            // ============================================
            const axios = require('axios');
            const fs = require('fs');
            const path = require('path');
            const archiver = require('archiver');
            
            const TOKEN = "XX"
            
            const API_BASE_URL = 'https://www.call2all.co.il/ym/api/';
            const ITEMS_PER_REQUEST = 500;
            
            // ============================================
            // פונקציות עזר
            // ============================================
            
            /**
             * יצירת תיקייה אם לא קיימת
             */
            function ensureDir(dirPath) {
              if (!fs.existsSync(dirPath)) {
                fs.mkdirSync(dirPath, { recursive: true });
              }
            }
            
            /**
             * מחיקת תיקייה רקורסיבית
             */
            function removeDir(dirPath) {
              if (fs.existsSync(dirPath)) {
                fs.rmSync(dirPath, { recursive: true, force: true });
              }
            }
            
            /**
             * קבלת פרטי המערכת
             */
            async function getSystemInfo() {
              try {
                const response = await axios.get(`${API_BASE_URL}GetSession`, {
                  params: {
                    token: TOKEN
                  }
                });
            
                if (response.data.responseStatus !== 'OK') {
                  throw new Error(`Error getting system info: ${response.data.message}`);
                }
            
                return response.data;
              } catch (error) {
                console.error('❌ שגיאה בקבלת פרטי מערכת:', error.message);
                throw error;
              }
            }
            
            /**
             * קבלת תוכן תיקייה מהשרת
             */
            async function getDirectoryContent(dirPath, filesFrom = 0, filesLimit = ITEMS_PER_REQUEST) {
              try {
                const response = await axios.get(`${API_BASE_URL}GetIVR2Dir`, {
                  params: {
                    token: TOKEN,
                    path: dirPath,
                    filesFrom,
                    filesLimit
                  }
                });
            
                if (response.data.responseStatus !== 'OK') {
                  throw new Error(`Error getting directory: ${response.data.message}`);
                }
            
                return response.data;
              } catch (error) {
                console.error(`❌ שגיאה בקבלת תוכן תיקייה ${dirPath}:`, error.message);
                throw error;
              }
            }
            
            /**
             * הורדת קובץ בודד
             */
            async function downloadFile(filePath, localPath) {
              try {
                const response = await axios.get(`${API_BASE_URL}DownloadFile`, {
                  params: {
                    token: TOKEN,
                    path: filePath
                  },
                  responseType: 'arraybuffer'
                });
            
                ensureDir(path.dirname(localPath));
                fs.writeFileSync(localPath, response.data);
                
                return true;
              } catch (error) {
                console.error(`❌ שגיאה בהורדת קובץ ${filePath}:`, error.message);
                return false;
              }
            }
            
            /**
             * איסוף כל הקבצים מתיקייה (עם טיפול בפגינציה) - ללא הורדה
             */
            async function collectFilesFromDir(dirPath) {
              let filesFrom = 0;
              let allFiles = [];
              let allIni = [];
              let allHtml = [];
            
              // איסוף כל הקבצים (עם פגינציה)
              while (true) {
                const dirContent = await getDirectoryContent(dirPath, filesFrom, ITEMS_PER_REQUEST);
                
                const currentFiles = dirContent.files || [];
                const currentIni = dirContent.ini || [];
                const currentHtml = dirContent.html || [];
            
                allFiles.push(...currentFiles);
                allIni.push(...currentIni);
                allHtml.push(...currentHtml);
            
                // אם קיבלנו פחות מהלימיט, זה אומר שזה הסיבוב האחרון
                if (currentFiles.length < ITEMS_PER_REQUEST) {
                  break;
                }
            
                filesFrom += ITEMS_PER_REQUEST;
              }
            
              return [
                ...allFiles,
                ...allIni,
                ...allHtml
              ];
            }
            
            /**
             * סריקה רקורסיבית של כל התיקיות - רק איסוף נתיבים
             */
            async function scanRecursively(dirPath, localDirPath, filesList = []) {
              // איסוף הקבצים מהתיקייה הנוכחית
              const files = await collectFilesFromDir(dirPath);
              
              // הוספת הקבצים למערך עם הנתיב המקומי
              for (const file of files) {
                filesList.push({
                  remotePath: file.what,
                  localPath: path.join(localDirPath, file.name),
                  name: file.name,
                  size: file.size || 0
                });
              }
            
              // קבלת רשימת התיקיות
              const dirContent = await getDirectoryContent(dirPath, 0, ITEMS_PER_REQUEST);
              const dirs = dirContent.dirs || [];
            
              // עיבוד כל תיקייה באופן רקורסיבי
              for (const dir of dirs) {
                const subDirPath = dir.what;
                const localSubDirPath = path.join(localDirPath, dir.name);
                
                await scanRecursively(subDirPath, localSubDirPath, filesList);
              }
            
              return filesList;
            }
            
            /**
             * הורדת כל הקבצים עם התקדמות
             */
            async function downloadAllFiles(filesList, concurrency = 10) {
              let completed = 0;
              const total = filesList.length;
              const startTime = Date.now();
            
              console.log(`\n⬇️  מתחיל הורדת ${total} קבצים...\n`);
            
              // חלוקה לבאצ'ים להורדה מקבילית מבוקרת
              for (let i = 0; i < filesList.length; i += concurrency) {
                const batch = filesList.slice(i, i + concurrency);
                
                const downloadPromises = batch.map(async (file) => {
                  const success = await downloadFile(file.remotePath, file.localPath);
                  
                  completed++;
                  const percentage = Math.floor((completed / total) * 100);
                  const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
                  const estimatedTotal = total > 0 ? ((elapsed / completed) * total).toFixed(0) : 0;
                  const remaining = estimatedTotal - elapsed;
                  
                  // עדכון progress bar
                  const barLength = 30;
                  const filled = Math.floor((completed / total) * barLength);
                  const bar = '█'.repeat(filled) + '░'.repeat(barLength - filled);
                  
                  process.stdout.write(`\r[${completed}/${total}] ${bar} ${percentage}% | ${elapsed}s / ~${estimatedTotal}s`);
                  
                  return success;
                });
            
                await Promise.all(downloadPromises);
              }
            
              console.log('\n');
              return completed;
            }
            
            /**
             * יצירת קובץ ZIP
             */
            async function createZip(sourceDir, outputPath) {
              return new Promise((resolve, reject) => {
                const output = fs.createWriteStream(outputPath);
                const archive = archiver('zip', {
                  zlib: { level: 9 } // דחיסה מקסימלית
                });
            
                output.on('close', () => {
                  console.log(`\n📦 קובץ ZIP נוצר: ${outputPath}`);
                  console.log(`   גודל: ${(archive.pointer() / 1024 / 1024).toFixed(2)} MB`);
                  resolve();
                });
            
                archive.on('error', (err) => {
                  reject(err);
                });
            
                archive.pipe(output);
                archive.directory(sourceDir, false);
                archive.finalize();
              });
            }
            
            /**
             * פונקציה ראשית
             */
            async function main() {
              console.log('🚀 מתחיל תהליך גיבוי...\n');
            
              // בדיקת טוקן
              if (TOKEN === 'your-token-here') {
                console.error('❌ שגיאה: לא הוגדר טוקן! הדבק את הטוקן שלך בתחילת הקובץ.');
                process.exit(1);
              }
            
              const startTime = Date.now();
              const startDate = new Date();
              
              // יצירת פורמט תאריך מלא
              const year = startDate.getFullYear();
              const month = String(startDate.getMonth() + 1).padStart(2, '0');
              const day = String(startDate.getDate()).padStart(2, '0');
              const hours = String(startDate.getHours()).padStart(2, '0');
              const minutes = String(startDate.getMinutes()).padStart(2, '0');
              const seconds = String(startDate.getSeconds()).padStart(2, '0');
              const dateTimeStr = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
            
              try {
                // קבלת פרטי מערכת
                console.log('📋 מקבל פרטי מערכת...');
                const systemInfo = await getSystemInfo();
                const systemNumber = systemInfo.username || 'unknown';
                console.log(`   מערכת: ${systemNumber}`);
                console.log(`   שם: ${systemInfo.name || 'N/A'}\n`);
            
                // יצירת תיקייה זמנית עם אותו שם כמו הקובץ
                const backupName = `backup_${systemNumber}_${dateTimeStr}`;
                const TEMP_DIR = path.join(__dirname, `temp_${backupName}`);
                
                console.log('📁 יוצר תיקייה זמנית...');
                ensureDir(TEMP_DIR);
            
                // שלב 1: סריקה ואיסוף נתיבים
                console.log('🔍 שלב 1: סורק תיקיות ואוסף רשימת קבצים...\n');
                const allFiles = await scanRecursively('ivr2:/', TEMP_DIR);
                
                const totalSize = allFiles.reduce((sum, file) => sum + (file.size || 0), 0);
                const totalSizeMB = (totalSize / 1024 / 1024).toFixed(2);
                
                console.log(`\n✅ סריקה הושלמה!`);
                console.log(`   📊 נמצאו: ${allFiles.length} קבצים`);
                console.log(`   💾 גודל כולל: ${totalSizeMB} MB\n`);
            
                // שלב 2: הורדת קבצים
                console.log('⬇️  שלב 2: מוריד קבצים...');
                const successCount = await downloadAllFiles(allFiles, 10);
                
                console.log(`✅ הורדה הושלמה: ${successCount}/${allFiles.length} קבצים\n`);
            
                // יצירת קובץ ZIP
                const zipPath = path.join(__dirname, `${backupName}.zip`);
                
                console.log('\n📦 יוצר קובץ ZIP...');
                await createZip(TEMP_DIR, zipPath);
            
                // מחיקת תיקייה זמנית
                console.log('🧹 מנקה תיקייה זמנית...');
                removeDir(TEMP_DIR);
            
                const duration = ((Date.now() - startTime) / 1000 / 60).toFixed(2);
                console.log(`\n✅ הגיבוי הושלם בהצלחה!`);
                console.log(`⏱️  זמן כולל: ${duration} דקות`);
                console.log(`📁 קובץ הגיבוי: ${zipPath}`);
            
              } catch (error) {
                console.error('\n❌ שגיאה בתהליך הגיבוי:', error.message);
                
                // ניקוי במקרה של שגיאה
                if (TEMP_DIR) {
                  console.log('🧹 מנקה תיקייה זמנית...');
                  removeDir(TEMP_DIR);
                }
                
                process.exit(1);
              }
            }
            
            // הרצת התוכנית
            if (require.main === module) {
              main();
            }
            
            

            שים לב שצריך להתקין את הספריות ולכתוב טוקן.

            E תגובה 1 תגובה אחרונה
            0
            • יהודי טובי יהודי טוב

              @eido

              אם מעניין אותך יש לי את הקוד הזה בnode.
              שאני דבר ראשון מקבל את כל הנתיבים של הקבצים - שזה בקשות לא כבדות.
              ואח"כ אני עובר על כל הקבצים עם מידע כמה אחוז כבר ירד (ושומר לקובץ ZIP את מה שנוצר)

              
              
              // ============================================
              // ייבוא מודולים
              // ============================================
              const axios = require('axios');
              const fs = require('fs');
              const path = require('path');
              const archiver = require('archiver');
              
              const TOKEN = "XX"
              
              const API_BASE_URL = 'https://www.call2all.co.il/ym/api/';
              const ITEMS_PER_REQUEST = 500;
              
              // ============================================
              // פונקציות עזר
              // ============================================
              
              /**
               * יצירת תיקייה אם לא קיימת
               */
              function ensureDir(dirPath) {
                if (!fs.existsSync(dirPath)) {
                  fs.mkdirSync(dirPath, { recursive: true });
                }
              }
              
              /**
               * מחיקת תיקייה רקורסיבית
               */
              function removeDir(dirPath) {
                if (fs.existsSync(dirPath)) {
                  fs.rmSync(dirPath, { recursive: true, force: true });
                }
              }
              
              /**
               * קבלת פרטי המערכת
               */
              async function getSystemInfo() {
                try {
                  const response = await axios.get(`${API_BASE_URL}GetSession`, {
                    params: {
                      token: TOKEN
                    }
                  });
              
                  if (response.data.responseStatus !== 'OK') {
                    throw new Error(`Error getting system info: ${response.data.message}`);
                  }
              
                  return response.data;
                } catch (error) {
                  console.error('❌ שגיאה בקבלת פרטי מערכת:', error.message);
                  throw error;
                }
              }
              
              /**
               * קבלת תוכן תיקייה מהשרת
               */
              async function getDirectoryContent(dirPath, filesFrom = 0, filesLimit = ITEMS_PER_REQUEST) {
                try {
                  const response = await axios.get(`${API_BASE_URL}GetIVR2Dir`, {
                    params: {
                      token: TOKEN,
                      path: dirPath,
                      filesFrom,
                      filesLimit
                    }
                  });
              
                  if (response.data.responseStatus !== 'OK') {
                    throw new Error(`Error getting directory: ${response.data.message}`);
                  }
              
                  return response.data;
                } catch (error) {
                  console.error(`❌ שגיאה בקבלת תוכן תיקייה ${dirPath}:`, error.message);
                  throw error;
                }
              }
              
              /**
               * הורדת קובץ בודד
               */
              async function downloadFile(filePath, localPath) {
                try {
                  const response = await axios.get(`${API_BASE_URL}DownloadFile`, {
                    params: {
                      token: TOKEN,
                      path: filePath
                    },
                    responseType: 'arraybuffer'
                  });
              
                  ensureDir(path.dirname(localPath));
                  fs.writeFileSync(localPath, response.data);
                  
                  return true;
                } catch (error) {
                  console.error(`❌ שגיאה בהורדת קובץ ${filePath}:`, error.message);
                  return false;
                }
              }
              
              /**
               * איסוף כל הקבצים מתיקייה (עם טיפול בפגינציה) - ללא הורדה
               */
              async function collectFilesFromDir(dirPath) {
                let filesFrom = 0;
                let allFiles = [];
                let allIni = [];
                let allHtml = [];
              
                // איסוף כל הקבצים (עם פגינציה)
                while (true) {
                  const dirContent = await getDirectoryContent(dirPath, filesFrom, ITEMS_PER_REQUEST);
                  
                  const currentFiles = dirContent.files || [];
                  const currentIni = dirContent.ini || [];
                  const currentHtml = dirContent.html || [];
              
                  allFiles.push(...currentFiles);
                  allIni.push(...currentIni);
                  allHtml.push(...currentHtml);
              
                  // אם קיבלנו פחות מהלימיט, זה אומר שזה הסיבוב האחרון
                  if (currentFiles.length < ITEMS_PER_REQUEST) {
                    break;
                  }
              
                  filesFrom += ITEMS_PER_REQUEST;
                }
              
                return [
                  ...allFiles,
                  ...allIni,
                  ...allHtml
                ];
              }
              
              /**
               * סריקה רקורסיבית של כל התיקיות - רק איסוף נתיבים
               */
              async function scanRecursively(dirPath, localDirPath, filesList = []) {
                // איסוף הקבצים מהתיקייה הנוכחית
                const files = await collectFilesFromDir(dirPath);
                
                // הוספת הקבצים למערך עם הנתיב המקומי
                for (const file of files) {
                  filesList.push({
                    remotePath: file.what,
                    localPath: path.join(localDirPath, file.name),
                    name: file.name,
                    size: file.size || 0
                  });
                }
              
                // קבלת רשימת התיקיות
                const dirContent = await getDirectoryContent(dirPath, 0, ITEMS_PER_REQUEST);
                const dirs = dirContent.dirs || [];
              
                // עיבוד כל תיקייה באופן רקורסיבי
                for (const dir of dirs) {
                  const subDirPath = dir.what;
                  const localSubDirPath = path.join(localDirPath, dir.name);
                  
                  await scanRecursively(subDirPath, localSubDirPath, filesList);
                }
              
                return filesList;
              }
              
              /**
               * הורדת כל הקבצים עם התקדמות
               */
              async function downloadAllFiles(filesList, concurrency = 10) {
                let completed = 0;
                const total = filesList.length;
                const startTime = Date.now();
              
                console.log(`\n⬇️  מתחיל הורדת ${total} קבצים...\n`);
              
                // חלוקה לבאצ'ים להורדה מקבילית מבוקרת
                for (let i = 0; i < filesList.length; i += concurrency) {
                  const batch = filesList.slice(i, i + concurrency);
                  
                  const downloadPromises = batch.map(async (file) => {
                    const success = await downloadFile(file.remotePath, file.localPath);
                    
                    completed++;
                    const percentage = Math.floor((completed / total) * 100);
                    const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
                    const estimatedTotal = total > 0 ? ((elapsed / completed) * total).toFixed(0) : 0;
                    const remaining = estimatedTotal - elapsed;
                    
                    // עדכון progress bar
                    const barLength = 30;
                    const filled = Math.floor((completed / total) * barLength);
                    const bar = '█'.repeat(filled) + '░'.repeat(barLength - filled);
                    
                    process.stdout.write(`\r[${completed}/${total}] ${bar} ${percentage}% | ${elapsed}s / ~${estimatedTotal}s`);
                    
                    return success;
                  });
              
                  await Promise.all(downloadPromises);
                }
              
                console.log('\n');
                return completed;
              }
              
              /**
               * יצירת קובץ ZIP
               */
              async function createZip(sourceDir, outputPath) {
                return new Promise((resolve, reject) => {
                  const output = fs.createWriteStream(outputPath);
                  const archive = archiver('zip', {
                    zlib: { level: 9 } // דחיסה מקסימלית
                  });
              
                  output.on('close', () => {
                    console.log(`\n📦 קובץ ZIP נוצר: ${outputPath}`);
                    console.log(`   גודל: ${(archive.pointer() / 1024 / 1024).toFixed(2)} MB`);
                    resolve();
                  });
              
                  archive.on('error', (err) => {
                    reject(err);
                  });
              
                  archive.pipe(output);
                  archive.directory(sourceDir, false);
                  archive.finalize();
                });
              }
              
              /**
               * פונקציה ראשית
               */
              async function main() {
                console.log('🚀 מתחיל תהליך גיבוי...\n');
              
                // בדיקת טוקן
                if (TOKEN === 'your-token-here') {
                  console.error('❌ שגיאה: לא הוגדר טוקן! הדבק את הטוקן שלך בתחילת הקובץ.');
                  process.exit(1);
                }
              
                const startTime = Date.now();
                const startDate = new Date();
                
                // יצירת פורמט תאריך מלא
                const year = startDate.getFullYear();
                const month = String(startDate.getMonth() + 1).padStart(2, '0');
                const day = String(startDate.getDate()).padStart(2, '0');
                const hours = String(startDate.getHours()).padStart(2, '0');
                const minutes = String(startDate.getMinutes()).padStart(2, '0');
                const seconds = String(startDate.getSeconds()).padStart(2, '0');
                const dateTimeStr = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
              
                try {
                  // קבלת פרטי מערכת
                  console.log('📋 מקבל פרטי מערכת...');
                  const systemInfo = await getSystemInfo();
                  const systemNumber = systemInfo.username || 'unknown';
                  console.log(`   מערכת: ${systemNumber}`);
                  console.log(`   שם: ${systemInfo.name || 'N/A'}\n`);
              
                  // יצירת תיקייה זמנית עם אותו שם כמו הקובץ
                  const backupName = `backup_${systemNumber}_${dateTimeStr}`;
                  const TEMP_DIR = path.join(__dirname, `temp_${backupName}`);
                  
                  console.log('📁 יוצר תיקייה זמנית...');
                  ensureDir(TEMP_DIR);
              
                  // שלב 1: סריקה ואיסוף נתיבים
                  console.log('🔍 שלב 1: סורק תיקיות ואוסף רשימת קבצים...\n');
                  const allFiles = await scanRecursively('ivr2:/', TEMP_DIR);
                  
                  const totalSize = allFiles.reduce((sum, file) => sum + (file.size || 0), 0);
                  const totalSizeMB = (totalSize / 1024 / 1024).toFixed(2);
                  
                  console.log(`\n✅ סריקה הושלמה!`);
                  console.log(`   📊 נמצאו: ${allFiles.length} קבצים`);
                  console.log(`   💾 גודל כולל: ${totalSizeMB} MB\n`);
              
                  // שלב 2: הורדת קבצים
                  console.log('⬇️  שלב 2: מוריד קבצים...');
                  const successCount = await downloadAllFiles(allFiles, 10);
                  
                  console.log(`✅ הורדה הושלמה: ${successCount}/${allFiles.length} קבצים\n`);
              
                  // יצירת קובץ ZIP
                  const zipPath = path.join(__dirname, `${backupName}.zip`);
                  
                  console.log('\n📦 יוצר קובץ ZIP...');
                  await createZip(TEMP_DIR, zipPath);
              
                  // מחיקת תיקייה זמנית
                  console.log('🧹 מנקה תיקייה זמנית...');
                  removeDir(TEMP_DIR);
              
                  const duration = ((Date.now() - startTime) / 1000 / 60).toFixed(2);
                  console.log(`\n✅ הגיבוי הושלם בהצלחה!`);
                  console.log(`⏱️  זמן כולל: ${duration} דקות`);
                  console.log(`📁 קובץ הגיבוי: ${zipPath}`);
              
                } catch (error) {
                  console.error('\n❌ שגיאה בתהליך הגיבוי:', error.message);
                  
                  // ניקוי במקרה של שגיאה
                  if (TEMP_DIR) {
                    console.log('🧹 מנקה תיקייה זמנית...');
                    removeDir(TEMP_DIR);
                  }
                  
                  process.exit(1);
                }
              }
              
              // הרצת התוכנית
              if (require.main === module) {
                main();
              }
              
              

              שים לב שצריך להתקין את הספריות ולכתוב טוקן.

              E מנותק
              E מנותק
              eido
              כתב נערך לאחרונה על ידי
              #6

              @יהודי-טוב תודה, אבל אני צריך יותר "תוכנית עבודה", אני אמור לכתוב את זה בגוגל סקריפט, ושם יש הגבלה של 6 דקות, לכן חשוב לי שתהיה אפשרות לעצור ולהמשיך.

              I יהודי טובי 2 תגובות תגובה אחרונה
              0
              • E eido

                @יהודי-טוב תודה, אבל אני צריך יותר "תוכנית עבודה", אני אמור לכתוב את זה בגוגל סקריפט, ושם יש הגבלה של 6 דקות, לכן חשוב לי שתהיה אפשרות לעצור ולהמשיך.

                I מנותק
                I מנותק
                ivrtikshoret
                כתב נערך לאחרונה על ידי ivrtikshoret
                #7

                @eido
                לפעמים צריך לחשוב איך אתה כבן אדם היית עושה כזה דבר לו יצוייר שיש לך רק 6 דקות ביום לעשות את זה,
                לאחר מכן תוכל לחשוב איך לכתוב את זה בקוד.

                לדוגמא במקרה כזה אני חושב שאני הייתי כותב כל יום בדף עד איפה כבר עברתי ואיפה אני אוחז כך שאוכל להמשיך למחרת באותו מיקום שעצרתי, מה דעתך?

                E תגובה 1 תגובה אחרונה
                0
                • E eido

                  @יהודי-טוב תודה, אבל אני צריך יותר "תוכנית עבודה", אני אמור לכתוב את זה בגוגל סקריפט, ושם יש הגבלה של 6 דקות, לכן חשוב לי שתהיה אפשרות לעצור ולהמשיך.

                  יהודי טובי מנותק
                  יהודי טובי מנותק
                  יהודי טוב
                  כתב נערך לאחרונה על ידי
                  #8

                  @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                  אני צריך יותר "תוכנית עבודה"

                  אולי תעשה משהו בסגנון שמבצע ריצה כדי לקבל את כל הנתיבים של הקבצים.
                  ותשמור את זה כJSON בגוגל שיטס ששם תיצור נניח שורה לכל תהליך שרץ ובשמירה תפצל את הJSON לפי מספר קבצים או גודל קבצים - לכמה תאים בשורה של התהליך...

                  ואז תבצע תהליך כשכל תהליך מוריד את הקבצים בJSON של תא מסוים ובסיום קורא לאנדפוינט שמתקדם לתא הבא וכן הלאה..

                  E תגובה 1 תגובה אחרונה
                  0
                  • חגיח מנותק
                    חגיח מנותק
                    חגי
                    כתב נערך לאחרונה על ידי
                    #9

                    @dovid הביא לך את דרך המלך, אתה משתמש ברקורסיה רק בשביל להשיג את רשימת הנתיבים, אחרי שיש לך אותם במערך, כל מה שאתה צריך לשמור זה את המערך ומספר שמייצג עד איפה הגעת.
                    אם אתה לא מוכן לכתוב קוד רקורסיבי אז תבקש מchatgpt לכתוב לך, זו הדרך הכי קלה, אני בכלל לא יכול לחשוב איך קוד איטרטיבי יהיה אלגוריתמית פשוט יותר מאשר רקורסיבי, הוא יהיה חייב להיות בנוי בצורה יוצאת דופן ולא טריוויאלית בכלל.

                    E 2 תגובות תגובה אחרונה
                    0
                    • I ivrtikshoret

                      @eido
                      לפעמים צריך לחשוב איך אתה כבן אדם היית עושה כזה דבר לו יצוייר שיש לך רק 6 דקות ביום לעשות את זה,
                      לאחר מכן תוכל לחשוב איך לכתוב את זה בקוד.

                      לדוגמא במקרה כזה אני חושב שאני הייתי כותב כל יום בדף עד איפה כבר עברתי ואיפה אני אוחז כך שאוכל להמשיך למחרת באותו מיקום שעצרתי, מה דעתך?

                      E מנותק
                      E מנותק
                      eido
                      כתב נערך לאחרונה על ידי
                      #10

                      @ivrtikshoret 100% הבעיה שלי היא לתרגם את זה לאלגוריתם יעיל.

                      תגובה 1 תגובה אחרונה
                      0
                      • חגיח חגי

                        @dovid הביא לך את דרך המלך, אתה משתמש ברקורסיה רק בשביל להשיג את רשימת הנתיבים, אחרי שיש לך אותם במערך, כל מה שאתה צריך לשמור זה את המערך ומספר שמייצג עד איפה הגעת.
                        אם אתה לא מוכן לכתוב קוד רקורסיבי אז תבקש מchatgpt לכתוב לך, זו הדרך הכי קלה, אני בכלל לא יכול לחשוב איך קוד איטרטיבי יהיה אלגוריתמית פשוט יותר מאשר רקורסיבי, הוא יהיה חייב להיות בנוי בצורה יוצאת דופן ולא טריוויאלית בכלל.

                        E מנותק
                        E מנותק
                        eido
                        כתב נערך לאחרונה על ידי
                        #11

                        @חגי אתם נשמות טובות באמת, אבל אם ביקשתי לא רקורסיה, אז יש סיבה...

                        גם לזה, ה6 דקות לפעמים לא מספיקות, אני אומר מניסיון...

                        חגיח תגובה 1 תגובה אחרונה
                        0
                        • יהודי טובי יהודי טוב

                          @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                          אני צריך יותר "תוכנית עבודה"

                          אולי תעשה משהו בסגנון שמבצע ריצה כדי לקבל את כל הנתיבים של הקבצים.
                          ותשמור את זה כJSON בגוגל שיטס ששם תיצור נניח שורה לכל תהליך שרץ ובשמירה תפצל את הJSON לפי מספר קבצים או גודל קבצים - לכמה תאים בשורה של התהליך...

                          ואז תבצע תהליך כשכל תהליך מוריד את הקבצים בJSON של תא מסוים ובסיום קורא לאנדפוינט שמתקדם לתא הבא וכן הלאה..

                          E מנותק
                          E מנותק
                          eido
                          כתב נערך לאחרונה על ידי
                          #12

                          @יהודי-טוב כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                          @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                          אני צריך יותר "תוכנית עבודה"

                          אולי תעשה משהו בסגנון שמבצע ריצה כדי לקבל את כל הנתיבים של הקבצים.
                          ותשמור את זה כJSON בגוגל שיטס ששם תיצור נניח שורה לכל תהליך שרץ ובשמירה תפצל את הJSON לפי מספר קבצים או גודל קבצים - לכמה תאים בשורה של התהליך...

                          ואז תבצע תהליך כשכל תהליך מוריד את הקבצים בJSON של תא מסוים ובסיום קורא לאנדפוינט שמתקדם לתא הבא וכן הלאה..

                          זה מה שאני כרגע באמצע לעשות, ואנ יכאן בשביל למצוא את הדרך הנכונה

                          תגובה 1 תגובה אחרונה
                          0
                          • צבי-שצ מחובר
                            צבי-שצ מחובר
                            צבי-ש
                            כתב נערך לאחרונה על ידי
                            #13

                            אולי כדאי להפריד תהליכים...
                            תהליך ראשי, רץ על ימות עצמם ואוסף דאטה
                            תהליכים משניים מעבדים את הדאטה שצריך להוריד, לשמור, ולעדכן את המרכזי שהם סיימו ויכולים לקבל עבודה נוספת.
                            את התיכים המשניים אתה יכול לשכפל ולהריץ גם 10 כאלה, ותקבל כח עיבוד של 10 סקריפטים, עם כעין שרת מרכזי שינהל את זה, ולא 1 צולע

                            כיף לגלות דברים חדשים.
                            חוק ה-50-50-90: בכל פעם שיש סיכוי של 50-50 שמשהו יעבוד, יש סיכוי של 90 אחוז שהוא לא. מקור

                            תגובה 1 תגובה אחרונה
                            1
                            • חגיח חגי

                              @dovid הביא לך את דרך המלך, אתה משתמש ברקורסיה רק בשביל להשיג את רשימת הנתיבים, אחרי שיש לך אותם במערך, כל מה שאתה צריך לשמור זה את המערך ומספר שמייצג עד איפה הגעת.
                              אם אתה לא מוכן לכתוב קוד רקורסיבי אז תבקש מchatgpt לכתוב לך, זו הדרך הכי קלה, אני בכלל לא יכול לחשוב איך קוד איטרטיבי יהיה אלגוריתמית פשוט יותר מאשר רקורסיבי, הוא יהיה חייב להיות בנוי בצורה יוצאת דופן ולא טריוויאלית בכלל.

                              E מנותק
                              E מנותק
                              eido
                              כתב נערך לאחרונה על ידי
                              #14

                              @חגי אגב, לא אמרתי שהוא יותר פשוט, אמרתי שלי הוא יותר יעיל...
                              אני מציע לכם לנסות פעם לכתוב קוד לארדואינו או esp8266, זה משנה חשיבה.

                              תגובה 1 תגובה אחרונה
                              -1
                              • E eido

                                @חגי אתם נשמות טובות באמת, אבל אם ביקשתי לא רקורסיה, אז יש סיבה...

                                גם לזה, ה6 דקות לפעמים לא מספיקות, אני אומר מניסיון...

                                חגיח מנותק
                                חגיח מנותק
                                חגי
                                כתב נערך לאחרונה על ידי חגי
                                #15

                                @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                                @חגי אתם נשמות טובות באמת, אבל אם ביקשתי לא רקורסיה, אז יש סיבה...

                                גם לזה, ה6 דקות לפעמים לא מספיקות, אני אומר מניסיון...

                                אני אומר לך שאם רקורסיה לא טובה מספיק בשבילך, אז שום דבר לא יהיה מספיק טוב בשבילך, הרקורסיה היא יעילה בזמן ריצה, החיסרון הלא מובהק שלה הוא שהיא צוברת זיכרון בשביל לזכור את הריצות הקודמות לפני שהיא מסיימת, אם לא נתקלת במגבלת זיכרון אלא במגבלת זמן, אז הבעיה שלך היא לא הרקורסיה.

                                @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                                אני מציע לכם לנסות פעם לכתוב קוד לארדואינו או esp8266, זה משנה חשיבה.

                                גם בארדואינו לעץ תיקיות בגודל שיכול להיכנס במחסנית הזיכרון גם הייתי ממליץ את זה, בארדואינו הבעיה שלך היא הפוכה, הזיכרון קטן וזמן הריצה בלתי מוגבל, זה בדיוק הפוך מהמקרה שלך.

                                E תגובה 1 תגובה אחרונה
                                1
                                • חגיח חגי

                                  @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                                  @חגי אתם נשמות טובות באמת, אבל אם ביקשתי לא רקורסיה, אז יש סיבה...

                                  גם לזה, ה6 דקות לפעמים לא מספיקות, אני אומר מניסיון...

                                  אני אומר לך שאם רקורסיה לא טובה מספיק בשבילך, אז שום דבר לא יהיה מספיק טוב בשבילך, הרקורסיה היא יעילה בזמן ריצה, החיסרון הלא מובהק שלה הוא שהיא צוברת זיכרון בשביל לזכור את הריצות הקודמות לפני שהיא מסיימת, אם לא נתקלת במגבלת זיכרון אלא במגבלת זמן, אז הבעיה שלך היא לא הרקורסיה.

                                  @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                                  אני מציע לכם לנסות פעם לכתוב קוד לארדואינו או esp8266, זה משנה חשיבה.

                                  גם בארדואינו לעץ תיקיות בגודל שיכול להיכנס במחסנית הזיכרון גם הייתי ממליץ את זה, בארדואינו הבעיה שלך היא הפוכה, הזיכרון קטן וזמן הריצה בלתי מוגבל, זה בדיוק הפוך מהמקרה שלך.

                                  E מנותק
                                  E מנותק
                                  eido
                                  כתב נערך לאחרונה על ידי
                                  #16

                                  @חגי קודם כל, תודה.
                                  יש גם מגבלת זכרון, פשוט אין לי קווים כ"כ גדולים בשביל לבדוק את זה, אבל אני רוצה לתת מענה גם להם.
                                  אין ספק שרקורסיה זו שיטה מהירה, היא השיטה שאיתה התחלתי את הפרוייקט, הענין הוא שצריך לעצור כל פחות מ6 דקות ולהמשיך הלאה, כמו שאמרתי, אין לי את הידע והזמן בשביל לכתוב סקריפט שיעשה את זה, מבחינתי יותר קל לי לכתוב קוד אטרטיבי שיהיה אפשר לעצור ולהמשיך. והכל במבנה התיקיות שאני רוצה.

                                  נכון, בארדואינו הזכרון מוגבל מאוד וזמן ריצה, כולו שלך, אבל גם כאן הזכרון לא בידיים שלך. וכשמדובר על קו עם אלפי שלוחות ועוד יותר הרבה הודעות, בקלות מגיעים למכסות.

                                  חגיח תגובה 1 תגובה אחרונה
                                  0
                                  • E eido

                                    @חגי קודם כל, תודה.
                                    יש גם מגבלת זכרון, פשוט אין לי קווים כ"כ גדולים בשביל לבדוק את זה, אבל אני רוצה לתת מענה גם להם.
                                    אין ספק שרקורסיה זו שיטה מהירה, היא השיטה שאיתה התחלתי את הפרוייקט, הענין הוא שצריך לעצור כל פחות מ6 דקות ולהמשיך הלאה, כמו שאמרתי, אין לי את הידע והזמן בשביל לכתוב סקריפט שיעשה את זה, מבחינתי יותר קל לי לכתוב קוד אטרטיבי שיהיה אפשר לעצור ולהמשיך. והכל במבנה התיקיות שאני רוצה.

                                    נכון, בארדואינו הזכרון מוגבל מאוד וזמן ריצה, כולו שלך, אבל גם כאן הזכרון לא בידיים שלך. וכשמדובר על קו עם אלפי שלוחות ועוד יותר הרבה הודעות, בקלות מגיעים למכסות.

                                    חגיח מנותק
                                    חגיח מנותק
                                    חגי
                                    כתב נערך לאחרונה על ידי חגי
                                    #17

                                    @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                                    אטרטיבי שיהיה אפשר לעצור ולהמשיך. והכל במבנה התיקיות שאני רוצה.

                                    לא קיים, אז אתה מתיאש מהפרוייקט או שאתה מנסה לשמור את המצב שלך איכשהו?
                                    אם הרקורסיה לא נתנה לך מענה אז תהיה בטוח שקוד איטרטיבי יהיה פחות טוב מזה.

                                    יכול להיות שאני לא לגמרי מבין את הבעיה שלך, יש לך מבנה של כל התיקיות שאתה משיג עם רקורסיה, אני משער שעם עץ של אלפי תיקיות אתה משיג את רשימת כל הנתיבים תוך שניה וחצי לכל היותר, אז איפה אתה נתקע על 6 דקות?
                                    בשלב שיש לך כבר רשימה של כל העץ תיקיות זה איטרטיבי לגמרי, תעשה עם הרשימה הזו מה שבא לך.
                                    ואם אנחנו מדברים על מיליוני קבצים, אז אני לא רואה איך קוד איטרטיבי יעזור לך, הוא לא ימפה את הקבצים יותר מהר.

                                    E תגובה 1 תגובה אחרונה
                                    0
                                    • חגיח חגי

                                      @eido כתב במעבר על תיקיות ותתי תיקיות על כל קבציהן בלי רקורסיה:

                                      אטרטיבי שיהיה אפשר לעצור ולהמשיך. והכל במבנה התיקיות שאני רוצה.

                                      לא קיים, אז אתה מתיאש מהפרוייקט או שאתה מנסה לשמור את המצב שלך איכשהו?
                                      אם הרקורסיה לא נתנה לך מענה אז תהיה בטוח שקוד איטרטיבי יהיה פחות טוב מזה.

                                      יכול להיות שאני לא לגמרי מבין את הבעיה שלך, יש לך מבנה של כל התיקיות שאתה משיג עם רקורסיה, אני משער שעם עץ של אלפי תיקיות אתה משיג את רשימת כל הנתיבים תוך שניה וחצי לכל היותר, אז איפה אתה נתקע על 6 דקות?
                                      בשלב שיש לך כבר רשימה של כל העץ תיקיות זה איטרטיבי לגמרי, תעשה עם הרשימה הזו מה שבא לך.
                                      ואם אנחנו מדברים על מיליוני קבצים, אז אני לא רואה איך קוד איטרטיבי יעזור לך, הוא לא ימפה את הקבצים יותר מהר.

                                      E מנותק
                                      E מנותק
                                      eido
                                      כתב נערך לאחרונה על ידי eido
                                      #18

                                      @חגי השגת הכתובות לוקחת הרבה זמן כי כל תיקיה זה שליחת בקשה חדשה והבקשות לוקחות זמן כמו שאמר dovid. מעבר לזה, המעבר על הקבצים בתיקיות ושמירתם ברשימה כלשהיא, גם כן לוקח זמן, זה בקלות עובר את ה6 דקות.

                                      רקורסיה היתה מושלמת עד שגיליתי את מגבלת ה6 דקות, אז נוצר מצב שצריך להפסיק באמצע, וכאן אנחנו חוזרים לאותן הטענות כמו עד עכשיו...

                                      רק להמחשה, עץ נתיבים של בערך 10 תיקיות עם קצת תת תיקיות ולא הרבה קבצים בתוכן לוקח קרוב ל5 דקות!

                                      תגובה 1 תגובה אחרונה
                                      0
                                      • dovidD dovid נעל נושא זה
                                      תגובה
                                      • תגובה כנושא
                                      התחברו כדי לפרסם תגובה
                                      • מהישן לחדש
                                      • מהחדש לישן
                                      • הכי הרבה הצבעות


                                      בא תתחבר לדף היומי!
                                      • התחברות

                                      • אין לך חשבון עדיין? הרשמה

                                      • התחברו או הירשמו כדי לחפש.
                                      • פוסט ראשון
                                        פוסט אחרון
                                      0
                                      • דף הבית
                                      • קטגוריות
                                      • פוסטים אחרונים
                                      • משתמשים
                                      • חיפוש
                                      • חוקי הפורום