التعامل مع ملفات JSON الكبيرة
تقنيات وأفضل الممارسات للتعامل مع ملفات JSON الكبيرة بكفاءة. أمثلة عملية للقراءة والمعالجة.
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# التعامل مع ملفات JSON الكبيرة
تعلم كيفية معالجة ملفات JSON الكبيرة بكفاءة دون استنزاف الذاكرة.
التحديات
المشاكل الشائعة
- استهلاك الذاكرة - تحميل الملف بالكامل
- بطء المعالجة - تحليل بيانات ضخمة
- فشل التطبيق - نفاد الذاكرة
- الأداء - وقت استجابة طويل
متى يعتبر JSON كبيراً؟
- صغير: < 1 MB
- متوسط: 1-10 MB
- كبير: 10-100 MB
- ضخم: > 100 MB
الحلول الأساسية
1. القراءة بالتدفق (Streaming)
بدلاً من تحميل الملف بالكامل، اقرأ جزءاً تلو الآخر.
2. المعالجة بالدفعات
معالجة البيانات على دفعات صغيرة.
3. التخزين المؤقت
احفظ النتائج لتجنب إعادة المعالجة.
التدفق في Node.js
باستخدام JSONStream
const fs = require('fs');
const JSONStream = require('JSONStream');
// قراءة ملف كبير
const stream = fs.createReadStream('large.json');
const parser = JSONStream.parse('users.');
parser.on('data', (user) => {
// معالجة كل مستخدم على حدة
console.log(user.name);
});
parser.on('end', () => {
console.log('انتهت المعالجة');
});
stream.pipe(parser);
معالجة مصفوفات كبيرة
const fs = require('fs');
const JSONStream = require('JSONStream');
const readStream = fs.createReadStream('large.json');
const writeStream = fs.createWriteStream('filtered.json');
// تصفية وكتابة
readStream
.pipe(JSONStream.parse('users.'))
.pipe(JSONStream.stringify('{"users":[', ',', ']}'))
.pipe(writeStream);
باستخدام stream-json
const { chain } = require('stream-chain');
const { parser } = require('stream-json');
const { streamArray } = require('stream-json/streamers/StreamArray');
const fs = require('fs');
const pipeline = chain([
fs.createReadStream('large.json'),
parser(),
streamArray(),
(data) => {
const { value } = data;
// معالجة كل عنصر
if (value.age > 30) {
return value;
}
}
]);
pipeline.on('data', (data) => {
console.log(data);
});
التدفق في Python
باستخدام ijson
import ijson
# قراءة ملف كبير
with open('large.json', 'rb') as f:
# معالجة كل عنصر
parser = ijson.items(f, 'users.item')
for user in parser:
print(user['name'])
# معالجة المستخدم
تصفية وحفظ
import ijson
import json
# قراءة وتصفية
filtered_users = []
with open('large.json', 'rb') as f:
parser = ijson.items(f, 'users.item')
for user in parser:
if user['age'] > 30:
filtered_users.append(user)
# حفظ النتائج
with open('filtered.json', 'w', encoding='utf-8') as f:
json.dump(filtered_users, f, ensure_ascii=False, indent=2)
معالجة متقدمة
import ijson
def process_large_file(filename):
"""معالجة ملف JSON كبير بكفاءة"""
count = 0
total_age = 0
with open(filename, 'rb') as f:
parser = ijson.items(f, 'users.item')
for user in parser:
count += 1
total_age += user.get('age', 0)
# معالجة كل 1000 مستخدم
if count % 1000 == 0:
print(f'معالجة {count} مستخدم...')
average_age = total_age / count if count > 0 else 0
return {
'total_users': count,
'average_age': average_age
}
# الاستخدام
stats = process_large_file('large.json')
print(stats)
المعالجة بالدفعات
Node.js
const fs = require('fs');
const JSONStream = require('JSONStream');
class BatchProcessor {
constructor(batchSize = 100) {
this.batchSize = batchSize;
this.batch = [];
}
async process(item) {
this.batch.push(item);
if (this.batch.length >= this.batchSize) {
await this.processBatch();
this.batch = [];
}
}
async processBatch() {
// معالجة الدفعة
console.log(معالجة ${this.batch.length} عنصر);
// مثال: حفظ في قاعدة البيانات
// await db.insertMany(this.batch);
}
async finish() {
// معالجة العناصر المتبقية
if (this.batch.length > 0) {
await this.processBatch();
}
}
}
// الاستخدام
async function processBigFile() {
const processor = new BatchProcessor(100);
const stream = fs.createReadStream('large.json');
const parser = JSONStream.parse('users.');
parser.on('data', async (user) => {
await processor.process(user);
});
parser.on('end', async () => {
await processor.finish();
console.log('اكتمل!');
});
stream.pipe(parser);
}
processBigFile();
Python
import ijson
import asyncio
class BatchProcessor:
def __init__(self, batch_size=100):
self.batch_size = batch_size
self.batch = []
async def process(self, item):
self.batch.append(item)
if len(self.batch) >= self.batch_size:
await self.process_batch()
self.batch = []
async def process_batch(self):
"""معالجة الدفعة"""
print(f'معالجة {len(self.batch)} عنصر')
# مثال: حفظ في قاعدة البيانات
# await db.insert_many(self.batch)
# محاكاة معالجة
await asyncio.sleep(0.1)
async def finish(self):
"""معالجة العناصر المتبقية"""
if self.batch:
await self.process_batch()
async def process_big_file(filename):
processor = BatchProcessor(100)
with open(filename, 'rb') as f:
parser = ijson.items(f, 'users.item')
for user in parser:
await processor.process(user)
await processor.finish()
print('اكتمل!')
# الاستخدام
asyncio.run(process_big_file('large.json'))
تحسين الذاكرة
مراقبة الاستخدام
// Node.js
const used = process.memoryUsage();
console.log(استخدام الذاكرة: ${Math.round(used.heapUsed / 1024 / 1024 100) / 100} MB);
# Python
import psutil
import os
process = psutil.Process(os.getpid())
memory_mb = process.memory_info().rss / 1024 / 1024
print(f'استخدام الذاكرة: {memory_mb:.2f} MB')
تنظيف الذاكرة
// Node.js - تشغيل garbage collector
if (global.gc) {
global.gc();
}
# Python
import gc
gc.collect()
JSON Lines (JSONL)
التنسيق
{"id": 1, "name": "أحمد", "age": 30}
{"id": 2, "name": "فاطمة", "age": 25}
{"id": 3, "name": "محمد", "age": 35}
قراءة JSONL
const fs = require('fs');
const readline = require('readline');
async function processJSONL(filename) {
const fileStream = fs.createReadStream(filename);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
const data = JSON.parse(line);
console.log(data.name);
}
}
processJSONL('data.jsonl');
import json
def process_jsonl(filename):
with open(filename, 'r', encoding='utf-8') as f:
for line in f:
data = json.loads(line)
print(data['name'])
process_jsonl('data.jsonl')
كتابة JSONL
const fs = require('fs');
const users = [
{ id: 1, name: 'أحمد' },
{ id: 2, name: 'فاطمة' }
];
const stream = fs.createWriteStream('output.jsonl');
users.forEach(user => {
stream.write(JSON.stringify(user) + '\n');
});
stream.end();
الضغط
Gzip
const fs = require('fs');
const zlib = require('zlib');
const JSONStream = require('JSONStream');
// قراءة ملف مضغوط
fs.createReadStream('data.json.gz')
.pipe(zlib.createGunzip())
.pipe(JSONStream.parse(''))
.on('data', (data) => {
console.log(data);
});
// كتابة ملف مضغوط
fs.createReadStream('data.json')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('data.json.gz'));
import gzip
import json
# قراءة ملف مضغوط
with gzip.open('data.json.gz', 'rt', encoding='utf-8') as f:
data = json.load(f)
# كتابة ملف مضغوط
with gzip.open('output.json.gz', 'wt', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False)
قواعد البيانات
تحميل إلى MongoDB
const fs = require('fs');
const JSONStream = require('JSONStream');
const { MongoClient } = require('mongodb');
async function loadToMongoDB(filename) {
const client = await MongoClient.connect('mongodb://localhost:27017');
const db = client.db('mydb');
const collection = db.collection('users');
const stream = fs.createReadStream(filename);
const parser = JSONStream.parse('users.');
let batch = [];
const BATCH_SIZE = 1000;
parser.on('data', async (user) => {
batch.push(user);
if (batch.length >= BATCH_SIZE) {
await collection.insertMany(batch);
batch = [];
}
});
parser.on('end', async () => {
if (batch.length > 0) {
await collection.insertMany(batch);
}
await client.close();
});
stream.pipe(parser);
}
استعلام من قاعدة البيانات
const { MongoClient } = require('mongodb');
async function streamFromDB() {
const client = await MongoClient.connect('mongodb://localhost:27017');
const collection = client.db('mydb').collection('users');
const cursor = collection.find({}).stream();
cursor.on('data', (doc) => {
console.log(doc.name);
});
cursor.on('end', () => {
client.close();
});
}
أفضل الممارسات
1. استخدم التدفق
// سيء - يحمل الملف بالكامل
const data = JSON.parse(fs.readFileSync('large.json'));
// جيد - يقرأ بالتدفق
const stream = fs.createReadStream('large.json');
stream.pipe(JSONStream.parse(''));
2. قسّم الملفات
قسم الملفات الكبيرة جداً إلى ملفات أصغر:
// تقسيم حسب الحجم
const MAX_SIZE = 10 1024 * 1024; // 10 MB
// أو حسب العدد
const MAX_ITEMS = 10000;
3. استخدم الفهارس
إذا كنت تبحث بشكل متكرر، استخدم قاعدة بيانات.
4. احفظ النتائج
// تخزين مؤقت للنتائج
const cache = new Map();
function processFile(filename) {
if (cache.has(filename)) {
return cache.get(filename);
}
const result = // معالجة الملف
cache.set(filename, result);
return result;
}
5. راقب الأداء
console.time('processing');
// معالجة
console.timeEnd('processing');
أدوات مفيدة
jq (سطر الأوامر)
# معالجة ملف كبير
jq '.users[] | select(.age > 30)' large.json
# حفظ النتائج
jq '.users[] | select(.age > 30)' large.json > filtered.json
# بدون تحميل في الذاكرة
cat large.json | jq -c '.users[]' | grep '"age":30'
Miller (mlr)
# تحويل JSON إلى CSV
mlr --ijson --ocsv cat data.json > data.csv
# تصفية
mlr --ijson --ojson filter '$age > 30' data.json
الملخص
للتعامل مع JSON الكبير:
- استخدم التدفق - لا تحمل كل شيء
- معالجة بالدفعات - قسّم المهمة
- راقب الذاكرة - تجنب النفاد
- استخدم الأدوات المناسبة - ijson, JSONStream
- فكر في البدائل - JSONL, قواعد البيانات
اختر الطريقة المناسبة لحجم بياناتك!
مقالات ذات صلة
Python و JSON: دليل شامل
تعلم كيفية العمل مع JSON في Python. القراءة، الكتابة، التحليل، والتحويل مع أمثلة عملية.
JavaScript و JSON: الدليل الكامل
تعلم كيفية العمل مع JSON في JavaScript. JSON.parse، JSON.stringify، وأفضل الممارسات.
JSON في علم البيانات
كيفية استخدام JSON في علم البيانات وتحليل البيانات. أمثلة عملية مع Python وPandas.