# File Uploads
Two distinct flows depending on the destination:
- **Channel @-reply with an image attachment** — read the file into a `Vec<u8>` and call `MessageParams::new_text(...).with_file_image(&bytes)`. See [`demo_at_reply_file_data.rs`](https://github.com/YinMo19/botrs/blob/main/examples/demo_at_reply_file_data.rs).
- **Group / C2C rich media** — upload a URL via `BotApi::post_group_file` / `BotApi::post_c2c_file`, deserialize the response into `Media`, then send a follow-up message with `msg_type: 7`. See [`demo_group_reply_file.rs`](https://github.com/YinMo19/botrs/blob/main/examples/demo_group_reply_file.rs) and [`demo_c2c_reply_file.rs`](https://github.com/YinMo19/botrs/blob/main/examples/demo_c2c_reply_file.rs).
## Channel attachment
```rust
let bytes = std::fs::read("examples/resource/test.png")?;
let params = MessageParams::new_text("here you go").with_file_image(&bytes);
ctx.api.post_message_with_params(&ctx.token, channel_id, params).await?;
```
## Group / C2C two-step
```rust
let upload = ctx.api.post_group_file(&ctx.token, group_openid, /* file_type */ 1, file_url, None).await?;
let media: botrs::models::message::Media = serde_json::from_value(upload)?;
let params = botrs::models::message::GroupMessageParams {
msg_type: 7, // 富媒体
msg_id: message.id.clone(),
media: Some(media),
..Default::default()
};
ctx.api.post_group_message_with_params(&ctx.token, group_openid, params).await?;
```
`post_c2c_file` + `post_c2c_message_with_params` follow the exact same pattern. `file_type` is `1` for image, see the demo file for other constants.
## See also
- Guide: [`docs/guide/messages.md`](../guide/messages.md)
- Demos: `examples/demo_at_reply_file_data.rs`, `examples/demo_group_reply_file.rs`, `examples/demo_c2c_reply_file.rs`