Click here to Skip to main content
15,888,527 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I want to use libcurl .net but there aren´t examples, the author provided a few ones but aren´t enough to a new coder like me. My code:

C#
private FileStream fileStream;
private void button2_Click(object sender, EventArgs e)
{
    fileStream = new FileStream("aaaaa.txt", FileMode.Create);

    Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);

    Easy easy = new Easy();
    Easy.WriteFunction wf = new Easy.WriteFunction(OnWriteData);

    easy.SetOpt(CURLoption.CURLOPT_URL, "http://www.google.com");
    easy.SetOpt(CURLoption.CURLOPT_WRITEFUNCTION, wf);

    easy.Perform();
    easy.Cleanup();

    Curl.GlobalCleanup();
}

public Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb, Object extraData)
{
    FileStream.Write(buf, 0, buf.Length);
    return size * nmemb;
}


As you can see I declare "private FileStream fileStream;" to be able to access the FileStream with "OnWriteData".
My problem is that I do not want to declare "private FileStream fileStream;" I want to declare the FileStream inside "private void button2_Click" and be able to write to it with "OnWriteData".

I hope that someone can understand me and can help me.
Posted
Updated 13-Jan-11 10:19am
v5

No need to declare FileStream fileStream outside the method using this object. Probably, you never should do it. This way, you're using a local variable instead of the class field. Always prefer local whenever possible. Do in under using block -- it will call Dispose automatically at the end of block even if there was an exception.

C#
using (fileStream stream = new FileStream("aaaaa.txt", FileMode.Create) {
    stream.Write//...
} //auto-call stream.Dispose();


You called Dispose anyway, which is very bad, you could have lost file records because nothing did the flush.

Also, you could better use StreamWriter instead:

C#
using (StreamWriter writer = new StreamWriter("aaaaa.txt") {
    writer.Write//...
    //you can access underlying stream from writer if needed
} //auto-call fileStream.Dispose();


Also, keyword "private" is C# default (for class or structure members -- thanks to Manfred for correction, see his comment below), can be omitted.

[EDIT] This is how to apply the same principle to Easy. First, implement System.IDisposable:

C#
public delegate System.Int32
    WriteData(
       FileStream stream, //added parameter
       byte[] buf, Int32 size, Int32 nmemb, bbject extraData);

class Easy : System.IDisposable {
    public Easy(FileStream stream, WriteData onWriteData) {
        this.Stream = stream;
        this.OnWriteData = onWriteData;
    } //Easy

    public void Perform() {
        //if (this.OnWriteData != null)
        //    OnWriteData(this.Stream, //...
    } //Perform
    void System.IDisposable.Dispose() {
        try { //important to make sure...
            CleanUp();
        } finally { //make sure Stream is always disposed:
            if (Stream != null)
                Stream.Dispose();
        } //exception
    } //System.IDisposable.Dispose
    void CleanUp() { /* ... */ }
    FileStream Stream;
} //System.IDisposable


This is how to use it:

C#
partial class MyForm {

    void MyButtonClickHandler() {
        using (Easy easy =
           new Easy(
                new FileStream("fname.aaa",
                FileMode.Create), OnWriteData)) {
            //..
            Easy.Perform();
            //..
        } //using -- clean-up here
    } //MyButtonClickHandler

    System.Int32 OnWriteData(
        FileStream stream,
            byte[] buf, Int32 size, Int32 nmemb, bbject extraData)
        {
        stream.Write(buf, 0, buf.Length);
        return size * nmemb;
    } //OnWriteData

} //class MyForm


Finally, this is how to use MyButtonClickHandler -- better way:

C#
MyButton.Click += (sender, eventArgs) => { MyButtonClickHandler(); };


I don't know your C# version, there is no lambda for v.2.0, but you still better of with anonymous:

C#
MyButton.Click += delegate( object sender, System.EventArgs eventArgs) {
   MyButtonClickHandler();
};
 
Share this answer
 
v5
Comments
Manfred Rudolf Bihy 13-Jan-11 16:22pm    
Access modifier "private" is the default for methods, fields, and properties in C#. Just to be exact! :)
Still 5+.
Sergey Alexandrovich Kryukov 16-Jan-11 17:46pm    
To be even more exact, to for class members; for example, in your statement events and private nested structures/classes are missing (what else?). Anyway, thanks a lot, I corrected my text.
Sergey Alexandrovich Kryukov 13-Jan-11 20:14pm    
Good correction. Thank you, Manfred.
Sergey Alexandrovich Kryukov 14-Jan-11 8:14am    
@Zeokat: Sorry, I omitted that detail with Easy.WriteFunction, this is my fault. But what I meant you should follow the idea. You do the cleanup in the same way. Instead of stream, you implement IDisposable in Easy, do its clean-up in its implementation IDisposable.Dispose, and use an instance of Easy created in the using "block". Call Stream.Dispose from Easy implementation of IDisposable.Dispose.

If this is not clear, I'll write it in code; I'll have some time for that within couple of hours.
Sergey Alexandrovich Kryukov 14-Jan-11 10:52am    
All right, I added how to use your Easy, please see the update.

Now, I have a big question: What's the purpose of abstracting out OnWriteData? What are the different implementations of this delegate? Event if there are different implementation, you would be better off making it a virtual method of the class Easy and use two or more different classes derived from Easy. How about that?
Thanks for the points but you not understand my question (perhaps is my fault since i can not explain good in english). If i follow your advice, i can use "using" but the scope is the scope, and i can´t access to it from "OnWriteData".

(I add as an asnwer because i can´t comment Manfred´s answer)
 
Share this answer
 
Comments
Manfred Rudolf Bihy 13-Jan-11 16:40pm    
SAKryukov meant that you should place the code he wrote inside the using statement into your OnWriteData method. That way you'll have access to it where you need it. OK?
Zeokat 13-Jan-11 23:19pm    
If i use this into OnWriteData method, each time a new file is created since onWrite is called several times from Easy.WriteFunction.

Thanks anyways, very apreciated your help.
Well, i want to code a multi-threaded file downloader/uploader with libcurl .net , i´m very new into c# (i´m using version .Net 3.5). And to work with threads i need a function that call each thread, and this function takes as argument the filename to download. Since i´m very new with .Net i have to study your code and your words very slowly to provide a better answer. Anyways thanks for all your time and all your help. I serached for libcurl examples and found one example to download a file but in c++ that was very simple:
#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <string>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
    size_t written;
    written = fwrite(ptr, size, nmemb, stream);
    return written;
}
int main(void) {
    CURL *curl;
    FILE *fp;
    CURLcode res;
    char *url = "http://localhost/aaa.txt";
    char outfilename[FILENAME_MAX] = "C:\\bbb.txt";
    curl = curl_easy_init();
    if (curl) {
        fp = fopen(outfilename,"wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        fclose(fp);
    }
    return 0;
}

I tryed to rewrite this code in c# and this is how everything started...
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900