# File::copyFileTo fails on iOS

**URL:** <https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306>\
**Category:** MacOSX and iOS\
**Created:** [January 24, 2020, 12:01pm UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306 "2020-01-24T12:01:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![adamwilson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/adamwilson/32/1387_2.png) [@adamwilson](https://forum.juce.com/u/adamwilson)\
**Post date:** [January 24, 2020, 12:01pm UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/1 "2020-01-24T12:01:40Z")

</div>

I’m trying to debug an issue on iOS where a call to `file.copyFileTo(newFile)` fails.

`jassert(newFile.hasWriteAccess());` passes.

The copyFile method:

```cpp
bool File::copyFileTo (const File& newFile) const
{
    return (*this == newFile)
            || (exists() && newFile.deleteFile() && copyInternal (newFile));
}

```

I have confirmed that `*this != newFile`  
The file does not exist.  
`deleteFile` returns true.

The debugger does not take me into `copyInternal` at all (I have a breakpoint set there).

Any clues?

---

<div class="post-metadata">

**Author:** ![ToxVox](https://avatars.discourse-cdn.com/v4/letter/t/76d3ee/32.png) [@ToxVox](https://forum.juce.com/u/ToxVox)\
**Post date:** [June 22, 2021, 11:49pm UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/2 "2021-06-22T23:49:08Z")

</div>

I run into the same iOS problem. It works fine on MacOS.

Does anyone have any new information?

---

<div class="post-metadata">

**Author:** ![ttg](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/ttg/32/14456_2.png) [@ttg](https://forum.juce.com/u/ttg)\
**Post date:** [June 23, 2021, 5:48am UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/3 "2021-06-23T05:48:20Z")

</div>

From where you’re trying to copy? are you using native FileChooser?  
If you’re trying to copy a file outside of your app (eg from iCloud/Local Device/Files) you need to use Url and maybe even handle input/output streams yourself.

---

<div class="post-metadata">

**Author:** ![ToxVox](https://avatars.discourse-cdn.com/v4/letter/t/76d3ee/32.png) [@ToxVox](https://forum.juce.com/u/ToxVox)\
**Post date:** [June 23, 2021, 8:52am UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/4 "2021-06-23T08:52:06Z")

</div>

Yes, I’m using the native FileChooser.

```auto
void FileManager::openFileChooser(
                                  const juce::String& dialogBoxTitle,
                                  const juce::File& initialFileOrDirectory,
                                  const juce::String& filePatternsAllowed,
                                  bool useOSNativeDialogBox,
                                  bool treatFilePackagesAsDirectories,
                                  Component* parentComponent,
                                  int FileChooserFlags)
{
    fileChooser.reset (new juce::FileChooser (dialogBoxTitle, initialFileOrDirectory, filePatternsAllowed, useOSNativeDialogBox));

    fileChooser->launchAsync (juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles,
                     [this] (const juce::FileChooser& chooser)
                     {
                        compoListeners.call([this](Listener &l)
                        {
                            l.fileChanged(this->fileChooser->getURLResult());
                        });
                     });
    
}

```

And here is the copy function:

```auto

void AppSoundControls::fileChanged (juce::URL url)
{
    juce::File selectedFile = url.getLocalFile();
    if(!selectedFile.exists())
    {
        DBG( __FUNCTION__ << " - No file selected " << selectedFile.getFullPathName());
        return;
    }
    DBG( __FUNCTION__ << " - Selected file exists: " << selectedFile.getFullPathName());
    
    const juce::File newFile = FileHelpers::getProjectsDir().getChildFile(processor.getProjectState().getProjectName()).getChildFile(Uuid().toString() + "_" + File::createLegalFileName(selectedFile.getFileName()));

    jassert(newFile.hasWriteAccess()); // No errors
    if(!selectedFile.copyFileTo(newFile))
    {
        DBG( __FUNCTION__ << " - Copy error: " << newFile.getFullPathName());
        return;
    }
    DBG( __FUNCTION__ << " - Copy success: " << newFile.getFullPathName());
}

```

As I said, this works on macOS.

---

<div class="post-metadata">

**Author:** ![ttg](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/ttg/32/14456_2.png) [@ttg](https://forum.juce.com/u/ttg)\
**Post date:** [June 23, 2021, 10:50am UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/5 "2021-06-23T10:50:54Z")

</div>

Sadly on iOS especially with Files supporting ‘cloud’ documents you’ll need to use the `InputStream` and write it yourself.

I wish JUCE would have some nice async/threaded mechanism built-in. sadly currently there’s none.

> [@iOS - FileInputStream::openHandle fails with FileChooser result](https://forum.juce.com/t/ios-fileinputstream-openhandle-fails-with-filechooser-result/37886/2):
>
> Are you using getURLResults to retrieve the file selected from the FileChooser ? (instead of getResults)

So after you get the inputstream properly, write it to a fileoutputstream in your ‘sandboxed’ / app writable path(s).

---

<div class="post-metadata">

**Author:** ![ToxVox](https://avatars.discourse-cdn.com/v4/letter/t/76d3ee/32.png) [@ToxVox](https://forum.juce.com/u/ToxVox)\
**Post date:** [June 23, 2021, 12:48pm UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/6 "2021-06-23T12:48:03Z")

</div>

Thanks for your hint @ttg !

It works now on iOS and MacOS:

```auto
void AppSoundControls::fileChanged (juce::URL url)
{
    auto inputStream = url.createInputStream(false);
    if(inputStream == nullptr)
    {
        DBG( __FUNCTION__ << " - Error: Can't create inputStream ");
        return;
    }
    else
        DBG( __FUNCTION__ << " - Ok: inputStream created");
    
    juce::File newFile = FileHelpers::getProjectsDir().getChildFile(processor.getProjectState().getProjectName()).getChildFile(Uuid().toString() + "_" + File::createLegalFileName(url.getLocalFile().getFileName()));
    if(!newFile.hasWriteAccess())
    {
        DBG( __FUNCTION__ << " - Error: No write access ");
        return;
    }
    
    std::unique_ptr<juce::FileOutputStream> outputStream;
    outputStream = newFile.createOutputStream();
    outputStream->writeFromInputStream(*inputStream, inputStream->getTotalLength());
}

```

---

<div class="post-metadata">

**Author:** ![phraemer](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/phraemer/32/10076_2.png) [@phraemer](https://forum.juce.com/u/phraemer)\
**Post date:** [October 7, 2022, 3:24pm UTC](https://forum.juce.com/t/file-copyfileto-fails-on-ios/37306/7 "2022-10-07T15:24:43Z")

</div>

To save someone else a bunch of wasted time debuging what’s wrong, be aware that `File::copyFileTo` will succeed on the iOS Similator but not on a real device.

Would be great to have the limitations of these functions documented.  
Or even better not make them available on platforms where they don’t work.
