Why does ContentManager.Load or TitleContainer.OpenStream say file not found?

Why does ContentManager.Load or TitleContainer.OpenStream say file not found?

  • Comments 6

The simple answer is that the file you are trying to load must not actually exist in the location you are trying to load it from!

And yet people sometimes get stuck on this error, unable to open their file and with no idea how to figure out why this is failing. I suspect this is a side effect of the Content Pipeline being so automated in XNA. When the usual experience is to just drop an image into Visual Studio, then ContentManager.Load it into your game, there is no need to learn the details of what happens to the file in between. But if you do not know this, you will not have the tools to debug when things go wrong, or to understand the differences between files built by the Content Pipeline versus deployed some other way.

In fact, the Content Pipeline is just an optional layer over the top of a simple file deployment mechanism. In order to load a file, exactly three things must take place:

  • The file must be copied to your build output folder
  • The file must be deployed from build output to the target device
  • You must specify the right name and path when you load it

 

Copy to build output folder

Your Visual Studio Solution Explorer contains source files, not build outputs. These source files are not directly available to your game at runtime. To make them available, we must copy them to the build output folder.

The build output folder is located inside whatever directory contains your project. This will typically be called something like bin\x86\Debug. There is a separate output folder for each target platform and build configuration (x86 vs. Xbox 360, Debug vs. Release, etc.)

There are three main ways to arrange for files to end up in this folder:

  1. Add files to your content project, so the Content Pipeline will compile them, creating .xnb format outputs which can be loaded using ContentManager.Load
  2. Add files to your main game project and set their Copy to Output Directory property to Copy if newer, so they will be copied directly to the output, from where they can be loaded using TitleContainer.OpenStream
  3. Customize your MSBuild project XML to add additional file copying tasks

To make sure all your files have been correctly copied, just open up the build output folder in Windows Explorer and take a look at what is there.

 

Deploy to the target device

When you debug a game on Windows, it runs directly from the build output folder, so no additional deployment is necessary.

When you run on Xbox or package as a .ccgame, the packaging tool gathers all the files from your build output folder (skipping only a few known-to-be-irrelevant formats such as .pdb), so all the same files are sure to be available even though the game actually runs elsewhere.

But on Windows Phone, or if you distribute a Windows game using ClickOnce, the deployment process only includes files that were declared as outputs by MSBuild. This includes all files created by the Content Pipeline or the Copy to Output Directory property, but will leave out anything you manually copied to the output folder, or if you incorrectly customized your MSBuild XML to copy files without also declaring them as build outputs (which is a topic for another day).

To make sure all your files have been correctly packaged for Windows Phone, rename the output .xap package to a .zip extension, so you can open it in Windows Explorer and see what it contains.

 

Specify the right name and path

TitleContainer.OpenStream paths are relative to the game executable. If the build output folder is bin\x86\Debug:

  • To load bin\x86\Debug\cats.txt, call TitleContainer.OpenStream("cats.txt")
  • To load bin\x86\Debug\Content\Levels\cats.txt, call TitleContainer.OpenStream("Content/Levels/cats.txt")

ContentManager.Load internally calls TitleContainer.OpenStream, but first it modifies the path in two ways:

  • It automatically adds the current value of ContentManager.RootDirectory in front of the supplied path
  • It automatically adds the .xnb file extension

So you should not include the .xnb extension when using ContentManager.Load (and also do not include the extension of whatever source file was used to create this .xnb - remember you are loading the compiled output file, not the source asset that was added to Visual Studio Solution Explorer).

The default game template sets ContentManager.RootDirectory to "Content", so:

  • To load bin\x86\Debug\Content\cat.xnb, call Content.Load<Texture2D>("cat")
  • To load bin\x86\Debug\Content\Levels\cat.xnb, call Content.Load<Texture2D>("Levels/cat")

You can create multiple ContentManager instances with whatever RootDirectory you like. For instance, to load bin\x86\Debug\Foo\Bar\cat.xnb, you could:

  • Set RootDirectory to String.Empty, then call Content.Load<Texture2D>("Foo/Bar/cat")
  • Set RootDirectory to "Foo/Bar", then call Content.Load<Texture2D>("cat")

Note: this article is about immutable content which is deployed as part of your game package. If you are looking to save and load data at runtime, you want Isolated Storage or StorageContainer instead.

  • "When you run on Xbox or package as a .ccgame, the packaging tool gathers all the files from your build output folder (skipping only a few known-to-be-irrelevant formats such as .pdb)"

    I wish it could be told not to package directories named ".svn"! If these accidentally make it into a .ccgame it will be rejected from AppHub submission form.

  • Why do you have .snv info in your build output directories?  It's not usually considered a good idea to check these generated output files into source control...

  • I know it's a borderline questionable thing to do... it's just copies of DLLs in the Bin directories that we have checked in. It's not a big deal, but it would be nice to be able to setup a custom filter to list extensions that should be ignored.

  • @Evan: A filter to filter out something that is not supposed to be happening in the first place is not warranted. The general rule is that a repository should only contain source code, assets and dependencies (such as other DLLs). If you own build output is in the repository, you should reconsider the repository layout.

  • Hi

    How do I know what path is currently used?!?!?!?!??!?!?!?!?!?!?!?!?!?!!?!?!?!?!

  • djhenrya: I don't understand your question. Used by what?

Page 1 of 1 (6 items)
Leave a Comment
  • Please add 3 and 6 and type the answer here:
  • Post