У меня сейчас нет времени на все объяснения (извините) s>,
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
{ "$lookup": {
"from": Tenant.collection.name,
"let": { "tenant": "$decks.tenant" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ " У меня сейчас нет времени на все объяснения (извините) s>,
Объяснение
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
[110] Отметив, что мы используем $mergeObjects
внутри $map
, чтобы сохранить существующее содержимое массива "decks"
и заменять только (или " merge ") перезаписанное представление "tenant"
для каждого члена массива. Вы уже используете выразительный $lookup
, и это подобно $mergeObjects
является функцией MongoDB 3.6.
Просто для интереса то же самое можно сделать, просто указав каждое поле в массиве. то есть:
"decks": {
"$map": {
"input": "$decks",
"in": {
"_id": "$this._id",
"number": "$this.number",
"tenant": {
// same expression
},
"__v": "$this.__v" // just because it's mongoose
}
}
}
То же самое можно сказать и о $REMOVE
, используемом в $addFields
, который также является другой особенностью MongoDB 3.6. Вы можете поочередно просто использовать $project
и просто опускать ненужные поля:
{ "$project": {
"number": "$number",
"decks": {
"$map": { /* same expression */ }
},
"__v": " У меня сейчас нет времени на все объяснения (извините) s>,
Объяснение
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
[110] Отметив, что мы используем $mergeObjects
внутри $map
, чтобы сохранить существующее содержимое массива "decks"
и заменять только (или " merge ") перезаписанное представление "tenant"
для каждого члена массива. Вы уже используете выразительный $lookup
, и это подобно $mergeObjects
является функцией MongoDB 3.6.
Просто для интереса то же самое можно сделать, просто указав каждое поле в массиве. то есть:
[111] То же самое можно сказать и о $REMOVE
, используемом в $addFields
, который также является другой особенностью MongoDB 3.6. Вы можете поочередно просто использовать $project
и просто опускать ненужные поля:
[112] Но в основном это работает. Взяв результат $lookup
и затем перенес эти результаты обратно в исходный массив в документе.
Пример списка
Также абстрагируясь от ваших данных из предыдущих вопросов здесь, что немного лучше, чем то, что вы опубликовали в вопросе здесь. Список для запуска для демонстрации:
const { Schema, Types: { ObjectId } } = mongoose = require('mongoose');
const uri = 'mongodb://localhost:27017/hotel';
const opts = { useNewUrlParser: true };
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndexes', true);
mongoose.set('debug', true);
const tenantSchema = new Schema({
name: String,
age: Number
});
const deckSchema = new Schema({
number: Number,
tenant: { type: Schema.Types.ObjectId, ref: 'Tenant' }
});
const bedSchema = new Schema({
number: Number,
decks: [deckSchema]
});
const roomSchema = new Schema({
bedspaces: [{ type: Schema.Types.ObjectId, ref: 'Bed' }]
});
const Tenant = mongoose.model('Tenant', tenantSchema);
const Bed = mongoose.model('Bed', bedSchema);
const Room = mongoose.model('Room', roomSchema);
const log = data => console.log(JSON.stringify(data, undefined, 2));
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// Clean data
await Promise.all(
Object.entries(conn.models).map(([k, m]) => m.deleteMany())
);
// Insert data
let [john, jane, bilbo ] = await Tenant.insertMany([
{
_id: ObjectId("5c964ae7f5097e3020d1926c"),
name: "john doe",
age: 11
},
{
_id: ObjectId("5c964b2531bc162fdce64f15"),
name: "jane doe",
age: 12
},
{
_id: ObjectId("5caa5454494558d863513b24"),
name: "bilbo",
age: 111
}
]);
let bedspaces = await Bed.insertMany([
{
_id: ObjectId("5c98d89c6bd5fc26a4c2851b"),
number: 1,
decks: [
{
number: 1,
tenant: john
},
{
number: 1,
tenant: jane
}
]
},
{
_id: ObjectId("5c98d89f6bd5fc26a4c28522"),
number: 2,
decks: [
{
number: 2,
tenant: bilbo
},
{
number: 3
}
]
}
]);
await Room.create({ bedspaces });
// Aggregate
let results = await Room.aggregate([
{ "$lookup": {
"from": Bed.collection.name,
"let": { "bedspaces": "$bedspaces" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ " У меня сейчас нет времени на все объяснения (извините) s>,
Объяснение
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
[110] Отметив, что мы используем $mergeObjects
внутри $map
, чтобы сохранить существующее содержимое массива "decks"
и заменять только (или " merge ") перезаписанное представление "tenant"
для каждого члена массива. Вы уже используете выразительный $lookup
, и это подобно $mergeObjects
является функцией MongoDB 3.6.
Просто для интереса то же самое можно сделать, просто указав каждое поле в массиве. то есть:
[111] То же самое можно сказать и о $REMOVE
, используемом в $addFields
, который также является другой особенностью MongoDB 3.6. Вы можете поочередно просто использовать $project
и просто опускать ненужные поля:
[112] Но в основном это работает. Взяв результат $lookup
и затем перенес эти результаты обратно в исходный массив в документе.
Пример списка
Также абстрагируясь от ваших данных из предыдущих вопросов здесь, что немного лучше, чем то, что вы опубликовали в вопросе здесь. Список для запуска для демонстрации:
[113] Возвращает:
Mongoose: tenants.deleteMany({}, {})
Mongoose: beds.deleteMany({}, {})
Mongoose: rooms.deleteMany({}, {})
Mongoose: tenants.insertMany([ { _id: 5c964ae7f5097e3020d1926c, name: 'john doe', age: 11, __v: 0 }, { _id: 5c964b2531bc162fdce64f15, name: 'jane doe', age: 12, __v: 0 }, { _id: 5caa5454494558d863513b24, name: 'bilbo', age: 111, __v: 0 } ], {})
Mongoose: beds.insertMany([ { _id: 5c98d89c6bd5fc26a4c2851b, number: 1, decks: [ { _id: 5caa5af6ed3dce1c3ed72cef, number: 1, tenant: 5c964ae7f5097e3020d1926c }, { _id: 5caa5af6ed3dce1c3ed72cee, number: 1, tenant: 5c964b2531bc162fdce64f15 } ], __v: 0 }, { _id: 5c98d89f6bd5fc26a4c28522, number: 2, decks: [ { _id: 5caa5af6ed3dce1c3ed72cf2, number: 2, tenant: 5caa5454494558d863513b24 }, { _id: 5caa5af6ed3dce1c3ed72cf1, number: 3 } ], __v: 0 } ], {})
Mongoose: rooms.insertOne({ bedspaces: [ ObjectId("5c98d89c6bd5fc26a4c2851b"), ObjectId("5c98d89f6bd5fc26a4c28522") ], _id: ObjectId("5caa5af6ed3dce1c3ed72cf3"), __v: 0 })
Mongoose: rooms.aggregate([ { '$lookup': { from: 'beds', let: { bedspaces: '$bedspaces' }, pipeline: [ { '$match': { '$expr': { '$in': [ ' У меня сейчас нет времени на все объяснения (извините) s>,
Объяснение
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
[110] Отметив, что мы используем $mergeObjects
внутри $map
, чтобы сохранить существующее содержимое массива "decks"
и заменять только (или " merge ") перезаписанное представление "tenant"
для каждого члена массива. Вы уже используете выразительный $lookup
, и это подобно $mergeObjects
является функцией MongoDB 3.6.
Просто для интереса то же самое можно сделать, просто указав каждое поле в массиве. то есть:
[111] То же самое можно сказать и о $REMOVE
, используемом в $addFields
, который также является другой особенностью MongoDB 3.6. Вы можете поочередно просто использовать $project
и просто опускать ненужные поля:
[112] Но в основном это работает. Взяв результат $lookup
и затем перенес эти результаты обратно в исходный массив в документе.
Пример списка
Также абстрагируясь от ваших данных из предыдущих вопросов здесь, что немного лучше, чем то, что вы опубликовали в вопросе здесь. Список для запуска для демонстрации:
[113] Возвращает:
[114] Показывает null
для второй записи второй записи в массиве bedspaces
, как и ожидалось.
id', '$bedspaces' ] } } }, { '$lookup': { from: 'tenants', let: { tenant: '$decks.tenant' }, pipeline: [ { '$match': { '$expr': { '$in': [ ' У меня сейчас нет времени на все объяснения (извините) s>,
Объяснение
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
[110] Отметив, что мы используем $mergeObjects
внутри $map
, чтобы сохранить существующее содержимое массива "decks"
и заменять только (или " merge ") перезаписанное представление "tenant"
для каждого члена массива. Вы уже используете выразительный $lookup
, и это подобно $mergeObjects
является функцией MongoDB 3.6.
Просто для интереса то же самое можно сделать, просто указав каждое поле в массиве. то есть:
[111] То же самое можно сказать и о $REMOVE
, используемом в $addFields
, который также является другой особенностью MongoDB 3.6. Вы можете поочередно просто использовать $project
и просто опускать ненужные поля:
[112] Но в основном это работает. Взяв результат $lookup
и затем перенес эти результаты обратно в исходный массив в документе.
Пример списка
Также абстрагируясь от ваших данных из предыдущих вопросов здесь, что немного лучше, чем то, что вы опубликовали в вопросе здесь. Список для запуска для демонстрации:
[113] Возвращает:
[114] Показывает null
для второй записи второй записи в массиве bedspaces
, как и ожидалось.
id', '$tenant' ] } } } ], as: 'tenant' } }, { '$addFields': { decks: { '$map': { input: '$decks', in: { '$mergeObjects': [ '$this', { tenant: [Object] } ] } } }, tenant: '$REMOVE' } } ], as: 'bedspaces' } } ], {})
[
{
"_id": "5caa5af6ed3dce1c3ed72cf3",
"bedspaces": [
{
"_id": "5c98d89c6bd5fc26a4c2851b",
"number": 1,
"decks": [
{
"_id": "5caa5af6ed3dce1c3ed72cef",
"number": 1,
"tenant": {
"_id": "5c964ae7f5097e3020d1926c",
"name": "john doe",
"age": 11,
"__v": 0
}
},
{
"_id": "5caa5af6ed3dce1c3ed72cee",
"number": 1,
"tenant": {
"_id": "5c964b2531bc162fdce64f15",
"name": "jane doe",
"age": 12,
"__v": 0
}
}
],
"__v": 0
},
{
"_id": "5c98d89f6bd5fc26a4c28522",
"number": 2,
"decks": [
{
"_id": "5caa5af6ed3dce1c3ed72cf2",
"number": 2,
"tenant": {
"_id": "5caa5454494558d863513b24",
"name": "bilbo",
"age": 111,
"__v": 0
}
},
{
"_id": "5caa5af6ed3dce1c3ed72cf1",
"number": 3,
"tenant": null
}
],
"__v": 0
}
],
"__v": 0
}
]
Показывает null
для второй записи второй записи в массиве bedspaces
, как и ожидалось.
id", "$bedspaces" ] }
}},
{ "$lookup": {
"from": Tenant.collection.name,
"let": { "tenant": "$decks.tenant" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ " У меня сейчас нет времени на все объяснения (извините) s>,
Объяснение
Основная проблема здесь заключается в том, что использование $unwind
это ваша проблема, и она вам не нужна. Вместо этого используйте $map
для содержимого созданного массива, сливающегося с массивом "decks"
. Тогда вы можете иметь nulls
.
Здесь вы хотите получить значения из $lookup
из вашей коллекции "tenants"
транспонировать в существующий массив в вашей коллекции "beds/bedspaces"
для своего собственного существующие значения "tenant"
, которые являются ссылками ObjectId
для зарубежной коллекции.
Этап $lookup
не может сделать это, просто назвав путь к полю в выходном сигнале "as"
, где этот путь уже находится внутри другого массива, и на самом деле в выходных данных $lookup
всегда всегда массив результатов, полученных из зарубежной коллекции. Вам нужно единичных значений для каждого фактического соответствия, и, конечно, вы ожидаете, что null
будет на месте, где ничего не совпадает, и, конечно, сохраните исходный массив документов "decks"
без изменений, но просто включите иностранные детали, где они были найдены.
Ваша попытка кода кажется частично осведомленной об этой точке, поскольку вы используете $unwind
для результата $lookup
в коллекции ""tenants"
в «временный массив» (но вы вставляете в существующий путь, который перезаписывает содержимое), а затем пытаетесь «перегруппировать» как массив через $group
и [1153 ] $push
. Но проблема, конечно, заключается в том, что результат $lookup
не применяется к каждому элементу массива в пределах "decks"
, поэтому вы получите меньше результатов, чем хотите.
Реальное решение не является «условным $lookup
» , но вместо этого транспонирует содержимое «1172]« временного массива » из результата в существующие записи "decks"
. Вы делаете это, используя $map
для обработки элементов массива, и $arrayElemAt
вместе с $indexOfArray
для возврата соответствующих элементов из [ 1173] «временный массив» путем сопоставления значений _id
и "tenant"
.
[110] Отметив, что
Не имеет значения вообще, локально ли это или глобально. Объем указателя файла не имеет никакого отношения к своему использованию.
В целом это - хорошая идея избежать глобальных переменных как можно больше.
Вот образец, показывающий, как скопировать с input.txt
кому: output.txt
:
#include <stdio.h>
int main(void) {
FILE *fin, *fout; int c;
// Open both files, fail fast if either no good.
if ((fin = fopen("input.txt", "r")) == NULL) {
fprintf(stderr, "Cannot read from input.txt");
return 1;
}
if ((fout = fopen("output.txt", "w")) == NULL) {
fprintf(stderr, "Cannot write to output.txt");
fclose(fin);
return 1;
}
// Transfer character by character.
while ((c = fgetc(fin)) >= 0) {
fputc (c, fout);
}
// Close both files and exit.
fclose(fin);
fclose(fout);
return 0;
}
Это - просто обычный указатель как любой другой.
FILE *CreateLogFile()
{
return fopen("logfile.txt","w"); // allocates a FILE object and returns a pointer to it
}
void UsefulFunction()
{
FILE *pLog = CreateLogFile(); // it's safe to return a pointer from a func
int resultsOfWork = DoSomeWork();
fprintf( pLog, "Work did %d\n", resultsOfWork ); // you can pass it to other functions
fclose( pLog ); // just be sure to clean it up when you are done with fclose()
pLog = NULL; // and it's a good idea to overwrite the pointer afterwards
// so it's obvious you deleted what it points to
}
Вот первый хит на Google для "файла io в c"
http://www.cs.bu.edu/teaching/c/file-io/intro/
Вот третий хит из gamedev с большим количеством наклона C++
http://www.gamedev.net/reference/articles/article1127.asp
Вы объявляете указатель в объеме, что Вам нужен он.
int main(void)
{
char c;
FILE *read;
read = fopen("myfile", "r"); // opens "myfile" for reading
if(read == NULL)
{
perror("Error: could not open \"myfile\" for reading.\n");
exit(1);
}
c = fgetc(read);
fclose(read);
printf("The first character of myfile is %c.\n", c);
return 0;
}
Вам отлично разрешают объявить глобальные дескрипторы файлов, если Вам нравится, точно так же, как какая-либо другая переменная, но она не может быть рекомендована.
Это - путь C. C++ может использовать это, но я думаю, что существует больше C++ дружественный способ сделать его. Как примечание, я ненавижу его, когда вопросами является отмеченный C/C++, потому что C и C++ не являются тем же языком и не работают то же. C++ имеет много различных способов сделать вещи, которые не имеет C, и они могут быть легче для Вас сделать в контексте C++, но не являются допустимым C. Таким образом, в то время как это будет работать на любой язык, это не то, что Вы хотите при преобладающем использовании C++.
Править: Добавленный некоторая проверка ошибок. Всегда используйте проверку ошибок в своем коде.
Во-первых, имейте в виду, что указатель файла (и связанная выделенная структура) основан на более низком открытом уровне () чтение () запись () вызовы. Связанный дескриптор файла (полученный fileno (file_pointer) является наименее интересной вещью, но что-то Вы могли бы хотеть наблюдать свой объем с.
Если Ваша попытка объявить указатель файла как глобальный в модуле, обычно очень хорошая идея сохранить это статичным (содержавший в том модуле / объектный файл). Иногда это немного легче, чем хранение его в структуре, которая передается от функции до функции, если необходимо записать что-то второпях.
Например, (плохо)
#include <stdio.h>
#include ...
#define MY_LOG_FILE "file.txt"
FILE *logfile
Лучше сделанный как:
#include <stdio.h>
#define MY_LOG_FILE "file.txt"
static FILE *logfile;
int main(void)
{
ЕСЛИ, Вам не нужны несколько модулей, чтобы иметь доступ к тому указателю, в этом случае Вы - более обеспеченное помещение его в структуре, которая может быть роздана.
Если его необходимое только в одном модуле, рассмотрите объявление его в основном () и разрешение другим функциям принять указатель файла как аргумент. Так, если Ваши функции в модуле не имеют столько аргументов, что другой был бы невыносим.. нет (обычно) никакой причины объявить указатель файла глобально.
Некоторые регистрирующиеся библиотеки делают это, о котором я не забочусь... особенно при контакте с повторно используемыми функциями. Монолитное пространство имен Nevermind C :)