Mike
Mike

Reputation: 8877

How can I use a resource to write line by line but still use Laravel's built in Storage?

I want to use Storage::put to write a file. The file is potentially very large (>100MB), so I want to utilise a stream so I don't blindly place everything into memory.

I'm going to be making multiple API requests, and then looping through their results, so the data I'll be getting back isn't an issue, it'll be limited to sensible amounts.

According to the documentation, I need to use:

Storage::put('file.xml', $resource);

But what would $resource be here?

Traditionally when writing files using PHP I have done it with a combination of fopen, fwrite and fclose in order to write 'line by line'. I'm building the file up by looping through various Collections and utlising various APIs as I go, so $resource is NOT a file pointer or file reference as is talked about elsewhere in the documentation.

So, how can I write line by line using a stream and Laravel's Storage?

Upvotes: 11

Views: 4938

Answers (3)

Milkmannetje
Milkmannetje

Reputation: 1181

I'd like to answer OP's comment:

As per my question, I'm not uploading a file, and I'm not streaming a file to another file. I am trying to write a plain-text file that I am building in-code in a streaming fashion. I have managed to write this very easily using fopen and fwrite, but would prefer the built-in Storage methods. I'm beginning to think it's not possible. – Mike Commented Oct 19, 2017 at 8:29

I think the power of Laravel's Filestorage system (Flysystem) is the abstraction it provides, so you can write files that are both local and somewhere in the cloud, all with the same API.

When you are working with files locally only and speed is the most important, you should stay with fopen(),fputs(),fwrite() etc... These functions work directly with the filesystem, instead of loading the files through PHP.

You can combine some of the features though. If you want to Unit test storing files, you can do something like:

Storage::fake('local');

$path = Storage::disk('local')->path("imports/output.csv");

$outputHandle = fopen($path, 'w');
fwrite($outputHandle, 'data');
fwrite($outputHandle, 'more data');

fclose($outputHandle);

This way, the Storage::fake() will handle storing the file on a temporary location, and cleaning up that files on each test run.

I hope this helps :)

Upvotes: 0

Alviero
Alviero

Reputation: 46

Storage::put('file.xml', $resource);

But what would $resource be here?

$resource is your data that you prepare to write to disk by code.

If you want to write the file with a loop you must use the Storage::append($file_name, $data); as wrote before by ljubadr

I wrote $data but you can use any name you want for a variable inside a loop.

Upvotes: 3

ljubadr
ljubadr

Reputation: 2254

Per Laravel 5.3 documentation, look into Automatic Streaming

If you would like Laravel to automatically manage streaming a given file to your storage location, you may use the putFile or putFileAs method. This method accepts either a Illuminate\Http\File or Illuminate\Http\UploadedFile instance and will automatically stream the file to your desire location:

You can upload file with streaming like this

$file = $request->file('file');
$path = \Storage::putFile('photos', $file);

Where your form input is

<input type="file" name="file">

Upvotes: 0

Related Questions