-2

I just wonder is it possible to store a file in a C# (Winform) project and create it when needed? The base scenario: my project uses a database file to store data (simple access .mdb file), and if it's not exist when opening the exe, it would create the stored one so the user could still use the program. (I need that database file, a simple txt would not suitable, it is a storage keeper app for my exam)

I doesn't even know how to search for it, it may not possible. I can't use a website to download the backed up file, it's not allowed for the exam.

North5014
  • 63
  • 7
  • 1
    Yes, you can include other files with your project. Project -> add -> existing item -> all file types -> browse to your file – Rufus L Nov 02 '20 at 17:43
  • And how can i create it for the user? If !File.Exist("database.mdb") { /*here how?*/ } – North5014 Nov 02 '20 at 17:47
  • Just create it ahead of time and add it to your project. Otherwise, I'm not sure I understand what this question is. Do you want to store a file or create a file? – Rufus L Nov 02 '20 at 17:49
  • You can add a Folder to your Project, name it `DataBases` (or some other name that doesn't use reserved words\terms), right-click the Folder -> Add Existing Item. Select your DB. Select the new Item in Solution Explorer: in its properties, set Build Action = none and Copy to OutputDirectory = Copy if newer. Your database is created each time you build the Project in the `DataBases` folder (`Debug\Databases` or `Release\Databases`), if a newer copy is not already there. – Jimi Nov 02 '20 at 17:50
  • For the particular case of a database, instead of bundling the default with the program, I would just have the scripts needed to create it from scratch (which would be a bunch of `CREATE TABLE` instructions) and run when needed to create the DB. That also fits well in the case of update the structure of existing databases (migrations). – Alejandro Nov 02 '20 at 17:54
  • Yes you may not understand. I want to counter the sitation when database.mdb is deleted from the user, either they created a new windows user or self deleted or something, then the program would "create" the stored database.mdb what is empty but at least they could still use the program. – North5014 Nov 02 '20 at 17:54
  • All right, then see what Kasra Sh proposed in the answer (Project's Resources) or what @Alejandro proposed: build the database form scratch if it's missing. An empty mdb database is really not that much, so you could add it as Resource. I'd build it from scratch, it's just a few lines of code and you have a *database builder* that can be *recycled*. – Jimi Nov 02 '20 at 18:00
  • Are there any tutorial out? Both way would be good. – North5014 Nov 02 '20 at 18:02
  • This is such a bizarre requirement – Caius Jard Nov 02 '20 at 18:03
  • @Alejandro (cc: @Jimi) - For a file-based database like Access, embedding a new, empty database as a resource is much easier than scripting DDL. Also, Access DDL is a bit wonky in places. – Gord Thompson Nov 02 '20 at 18:22
  • @Gord Thompson Because you may need to add a COM reference to `msadox.dll` and create the catalog yourself? Sure. At *this stage* it's probably better to add an empty database as an Additional File to the Project (maybe with a *facade* extension) or just an Embedded Resource (though I don't like to suggest something that adds clutter to the executable). – Jimi Nov 02 '20 at 18:49
  • @Gord Thompson If an Embedded Resource is acceptable, the OP can just take the hint from my first comment and change the `Build Type` in `Embedded Resource` and it's all done automatically. – Jimi Nov 02 '20 at 18:58

3 Answers3

3

Yeah, it's possible.

You can store files in a Dll or Executable by setting it as am embeded resource. So add the file to your project and then click on it in visual studio and change it's Build Action in the properties pane from "Content" to "Embeded Resource"

When you compile the program, this will cause the file to be included in the Executable or Dll's Resource sections in the binary.

In your code you can access embeded resources via the Assembly class in the System.Reflection namespace. The method is called "GetManifestResourceStream" and it's an instanced method. So you need to get a reference to the Assembly your embeded resource is in. If it's in the current executable just use System.Reflection.Assembly.GetEntryAssembly().

The GetManifestResourceStream method accepts a name for the name of the Embeded Resource. The name is determined by the namespace of the file you added as an embeded resource. So if you put the file in the root of the project then it will be whatever the projects default namespace is plus the name of the file.

So let's say you added "trees.png" and you put it in a folder called "Images" in the root of your Project. Now let's say the projects root namespace is XYZ.ImageEditor. So the name of the embedded resource to give to GetManifestResourceStream would be "XYZ.ImageEditor.Images.trees.png".

There is also a method called GetManifestResourceNames() that will return a list of all resource names embedded in the assembly, so the full name of trees.png would be returned in this list. You can use that to enumerate files embedded in the Assembly.

Once you have the resource stream you can write it to a file with System.IO.File.WriteAllText or System.IO.File.WriteAllBinary, etc etc. Or open a file stream manually and write to it from Bytes read from the resource stream. Lots of different ways to go about doing this part.

Ryan Mann
  • 5,178
  • 32
  • 42
  • Check out the other answer to as there is a resource system built into c# that automatically exposes resources to your code via Assembly properties. It generates a Resources.resx file that generates code for the Resources for you, so you can Access them via "XYZ.MyNamespaceHere.Resources.TreePNG" where TreePNG is the key you give the resource. – Ryan Mann Nov 02 '20 at 17:53
  • Okey but what i don't understand how can i create or copy the png next to the exe when it not exists, because the user deleted or something. (Or the database in my scenario) Are they anything like File.CreateFile(Resources.MyFile) ? – North5014 Nov 02 '20 at 17:56
  • Why would the user delete it but not the exe? If you're thinking the user has a random hate for mdb files, just rename a copy of the db as data.dll, then if you find the real database.mdb missing, file copy data.dll to database.mdb.. – Caius Jard Nov 02 '20 at 18:01
  • The database file can't be in C:\Program File\ MyProgram because of permissions to write, so it is placed to %AppData% and if the user switches to another profile in his windows the database will be missing. – North5014 Nov 02 '20 at 18:03
  • @North5014 - Yes, the data file should not be in %ProgramFiles% because of the permissions there, but your app could put it into %ProgramData% instead. – Gord Thompson Nov 02 '20 at 18:12
  • Yes but i want it to be different per user as my exam needs it. That's why i want to create a backup up (empty) database. – North5014 Nov 02 '20 at 18:15
  • @North5014 - Okay, then have your app save the file to %APPDATA% or %LOCALAPPDATA% as appropriate. (And remember to `@`-mention the person to whom you are replying like I did here.) – Gord Thompson Nov 02 '20 at 18:17
  • The MDB should be stored in %LocalAppData% Have your program create a folder in there for your program and create the MDB for the user from am embeded resource each time it's needed and not there. – Ryan Mann Nov 02 '20 at 18:18
1

What you are looking for is called Resources, resources are external assets like icons or background images, etc.

Perhaps this may be helpful: https://learn.microsoft.com/en-us/dotnet/framework/resources/creating-resource-files-for-desktop-apps

Kasra Sh
  • 21
  • 2
1

You can add your file to the project as embedded resource. At runtime if the file is missing you can get a stream off the resource and use that stream to write a file.

[edit] Add your file to the project as an existing file and set its build action to "Embedded resource". Note the default namespace. It will be the prefix to your resource. Here the project is CreateFileIfMissing.

    string filename = "test.png";
    if ( System.IO.File.Exists( filename ) == false )
    {
        var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream( $"CreateFileIfMissing.{filename}" );
        using ( var fileStream = System.IO.File.Create( filename ) )
        {
            stream.CopyTo( fileStream );
        }
    }
  • "At runtime if the file is missing you can get a stream off the resource and use that stream to write a file" Can you show me an example code please? I would appreciate so much. – North5014 Nov 02 '20 at 18:21
  • @North5014 - Stack Overflow is not a code-writing service. Try using the advice you've been given in the answers here to create your own code that (1) checks if a file exists on disk, and (2) saves a file (resource) from your app if it doesn't. If you get stuck then [ask a new question](https://stackoverflow.com/questions/ask) to show what you tried and describe *in detail* how it doesn't work. – Gord Thompson Nov 02 '20 at 18:31
  • At least you could tell me the command name @GordThompson – North5014 Nov 02 '20 at 18:32
  • @North5014 - https://stackoverflow.com/q/7385251/2144390 – Gord Thompson Nov 02 '20 at 18:42
  • We are not even talking about checking if file.exist but write from resources to disk... @GordThompson you're really not here to help me but just being toxic. – North5014 Nov 02 '20 at 18:44