זהו נושא דיון מלווה לערך המקורי שב־https://www.tocode.co.il/bundles/25/lessons/12-lab-files-and-directories
זהו נושא דיון מלווה לערך המקורי שב־https://www.tocode.co.il/bundles/25/lessons/12-lab-files-and-directories
הפתרון שלי למטלה 1
לא מצאתי דרך שהיא לא רקורסיבית למצוא את עץ התיקיות והקבצים… מקווה שהפתרון הזה מספיק אלגנטי.
הוספתי גם טופס קטן בתוך הclient שדרכו ניתן למעשה להוסיף קבצים או תיקיות בתוך התיקייה בשרת עצמו
const express = require("express")
const path = require("path")
const fsp = require("fs/promises")
const filesR = express.Router()
filesR.get("/", async (req, res, next) => {
const rootPath = path.join(__dirname, "..", "root")
const files = await getAllFilesRec(rootPath)
const list = listAllFiles(files)
res.send(`<div>
<ul>
<li><a href="/">home</a></li>
</ul>
<h2>welcome to the files route</h2>
${list}
<form id="form">
<input type="text" name="name" placeholder="add file or folder">
<select name="type">
<option value="file" selected>file</option>
<option value="folder">folder</option>
</select>
<input type="submit" value="add">
</form>
<script>
form.onsubmit = e => {
e.preventDefault()
const elements = document.querySelectorAll("input[name],select")
const data = {}
for(let elem of elements){
data[elem.name] = elem.value
}
const promise = fetch("/files/add",{method:"POST",body:JSON.stringify(data),headers:{"Content-Type":"application/json"}})
promise
.then(res=>res.json())
.then(json=>console.log(json))
.then(()=>form.reset())
.then(()=>window.location.href = window.location.href)
.catch(err=>console.error(err))
}
</script>
</div>`)
})
filesR.post("/print", async (req, res, next) => {
const projectPath = path.join(__dirname, "..")
const rootPath = path.join(projectPath, "root")
const files = await getAllFilesRec(rootPath)
await fsp.appendFile(
path.join(projectPath, "root-files.json"),
JSON.stringify(files),
{ encoding: "utf-8" }
)
res.status(200).json({
status: "success",
data: files
})
})
filesR.post("/add", async (req, res, next) => {
const { name = "noName", type = "file" } = req.body
let filePath = ""
if (type === "file") {
try {
filePath = path.join(__dirname, "..", "root", name)
if (name.indexOf("/") > -1) {
const fse = require("fs-extra")
await fse.outputFile(filePath, "", { encoding: "utf-8" })
} else {
await fsp.appendFile(filePath, "", { encoding: "utf-8" })
}
console.log(name + " created succesfully")
} catch (err) {
console.error("error on file creation ", err)
return res.status(500).json({
status: "fail",
error: err
})
}
} else if (type === "folder") {
try {
filePath = path.join(__dirname, "..", "root", name)
const folder = await fsp.mkdir(filePath, { recursive: true })
console.log(folder + " created succesfully")
} catch (err) {
console.error("error on folder creation ", err)
return res.status(500).json({
status: "fail",
error: err
})
}
}
return res.status(201).json({
status: "success",
path: filePath
})
})
async function getAllFilesRec(dir, files = {}) {
const nodes = await fsp.readdir(dir, { withFileTypes: true });
for (i in nodes) {
const node = nodes[i]
const location = path.join(dir, node.name)
if (node.isDirectory()) {
files[node.name] = {
name: node.name, location,
type: "folder",
files: Object.assign({}, await getAllFilesRec(location, {}))
}
} else {
files[node.name] = { name: node.name, location, type: "file" }
}
}
return files
}
function listAllFiles(files = {}, string = "<ul>") {
Object.entries(files).forEach(([fileName, fileData]) => {
if (fileData.type === "folder") {
string += `<li>
${fileName} [folder]
<ul>${listAllFiles(files[fileName].files, "")}
</li>`
} else {
string += `<li>${fileName} [file]</li>`
}
})
string += "</ul>"
return string
}
module.exports = filesR
הי,
הפיתרון נראה אחלה. תנסה עכשיו להחליף את ה readdir ב readdirSync ותמדוד זמנים בשתי האופציות, תראה איזו אופציה עובדת לך יותר מהר.
לגבי פיתרון לא רקורסיבי - בכל פעם שאתה רוצה להחליף פונקציה רקורסיבית בפונקציה לא רקורסיבית כדאי להשתמש במבנה נתונים מחסנית:
הוספה למחסנית היא כמו ״כניסה״ לפונקציה רקורסיבית והוצאה מהמחסנית מקבילה ל״חזרה״ מהקריאה הרקורסיבית